d3d11/tests: Add test for shaders interstage interface.
[wine.git] / dlls / user32 / tests / msg.c
blob1b4f6fa5259c103001bbfeaa0d9a9236163b7dcd
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 /* occasionally 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 /* occasionally 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 /* occasionally 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 /* occasionally 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 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1800 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1801 { 0 }
1804 static const struct message WmEnableWindowSeq_3[] =
1806 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1807 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1808 { 0 }
1811 static const struct message WmEnableWindowSeq_4[] =
1813 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1814 { 0 }
1817 static const struct message WmGetScrollRangeSeq[] =
1819 { SBM_GETRANGE, sent },
1820 { 0 }
1822 static const struct message WmGetScrollInfoSeq[] =
1824 { SBM_GETSCROLLINFO, sent },
1825 { 0 }
1827 static const struct message WmSetScrollRangeSeq[] =
1829 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1830 sends SBM_SETSCROLLINFO.
1832 { SBM_SETSCROLLINFO, sent },
1833 { 0 }
1835 /* SetScrollRange for a window without a non-client area */
1836 static const struct message WmSetScrollRangeHSeq_empty[] =
1838 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1839 { 0 }
1841 static const struct message WmSetScrollRangeVSeq_empty[] =
1843 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1844 { 0 }
1846 static const struct message WmSetScrollRangeHVSeq[] =
1848 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1849 { WM_NCCALCSIZE, sent|wparam, 1 },
1850 { WM_GETTEXT, sent|defwinproc|optional },
1851 { WM_ERASEBKGND, sent|optional },
1852 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1853 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1854 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1855 { 0 }
1857 /* SetScrollRange for a window with a non-client area */
1858 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1860 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1861 { WM_NCCALCSIZE, sent|wparam, 1 },
1862 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1863 { WM_NCPAINT, sent|optional },
1864 { WM_STYLECHANGING, sent|defwinproc|optional },
1865 { WM_STYLECHANGED, sent|defwinproc|optional },
1866 { WM_STYLECHANGING, sent|defwinproc|optional },
1867 { WM_STYLECHANGED, sent|defwinproc|optional },
1868 { WM_STYLECHANGING, sent|defwinproc|optional },
1869 { WM_STYLECHANGED, sent|defwinproc|optional },
1870 { WM_STYLECHANGING, sent|defwinproc|optional },
1871 { WM_STYLECHANGED, sent|defwinproc|optional },
1872 { WM_GETTEXT, sent|defwinproc|optional },
1873 { WM_GETTEXT, sent|defwinproc|optional },
1874 { WM_ERASEBKGND, sent|optional },
1875 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1876 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1877 { WM_SIZE, sent|defwinproc|optional },
1878 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1879 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1880 { WM_GETTEXT, sent|optional },
1881 { WM_GETTEXT, sent|optional },
1882 { WM_GETTEXT, sent|optional },
1883 { WM_GETTEXT, sent|optional },
1884 { 0 }
1886 /* test if we receive the right sequence of messages */
1887 /* after calling ShowWindow( SW_SHOWNA) */
1888 static const struct message WmSHOWNAChildInvisParInvis[] = {
1889 { WM_SHOWWINDOW, sent|wparam, 1 },
1890 { 0 }
1892 static const struct message WmSHOWNAChildVisParInvis[] = {
1893 { WM_SHOWWINDOW, sent|wparam, 1 },
1894 { 0 }
1896 static const struct message WmSHOWNAChildVisParVis[] = {
1897 { WM_SHOWWINDOW, sent|wparam, 1 },
1898 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1899 { 0 }
1901 static const struct message WmSHOWNAChildInvisParVis[] = {
1902 { WM_SHOWWINDOW, sent|wparam, 1 },
1903 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1904 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1905 { WM_ERASEBKGND, sent|optional },
1906 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1907 { 0 }
1909 static const struct message WmSHOWNATopVisible[] = {
1910 { WM_SHOWWINDOW, sent|wparam, 1 },
1911 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1912 { WM_NCPAINT, sent|wparam|optional, 1 },
1913 { WM_GETTEXT, sent|defwinproc|optional },
1914 { WM_ERASEBKGND, sent|optional },
1915 { WM_WINDOWPOSCHANGED, sent|optional },
1916 { 0 }
1918 static const struct message WmSHOWNATopInvisible[] = {
1919 { WM_NOTIFYFORMAT, sent|optional },
1920 { WM_QUERYUISTATE, sent|optional },
1921 { WM_WINDOWPOSCHANGING, sent|optional },
1922 { WM_GETMINMAXINFO, sent|optional },
1923 { WM_NCCALCSIZE, sent|optional },
1924 { WM_WINDOWPOSCHANGED, sent|optional },
1925 { WM_SHOWWINDOW, sent|wparam, 1 },
1926 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1927 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1928 { WM_NCPAINT, sent|wparam|optional, 1 },
1929 { WM_GETTEXT, sent|defwinproc|optional },
1930 { WM_ERASEBKGND, sent|optional },
1931 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1932 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1933 { WM_NCPAINT, sent|wparam|optional, 1 },
1934 { WM_ERASEBKGND, sent|optional },
1935 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1936 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1937 { WM_MOVE, sent },
1938 { 0 }
1941 static const struct message WmTrackPopupMenu[] = {
1942 { HCBT_CREATEWND, hook },
1943 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1944 { WM_INITMENU, sent|lparam, 0, 0 },
1945 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1946 { 0x0093, sent|optional },
1947 { 0x0094, sent|optional },
1948 { 0x0094, sent|optional },
1949 { WM_ENTERIDLE, sent|wparam, 2 },
1950 { WM_CAPTURECHANGED, sent },
1951 { HCBT_DESTROYWND, hook },
1952 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1953 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1954 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1955 { 0 }
1958 static const struct message WmTrackPopupMenuEsc[] = {
1959 { 0 }
1962 static const struct message WmTrackPopupMenuCapture[] = {
1963 { HCBT_CREATEWND, hook },
1964 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1965 { WM_CAPTURECHANGED, sent },
1966 { WM_INITMENU, sent|lparam, 0, 0 },
1967 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1968 { 0x0093, sent|optional },
1969 { 0x0094, sent|optional },
1970 { 0x0094, sent|optional },
1971 { WM_ENTERIDLE, sent|wparam, 2 },
1972 { WM_CAPTURECHANGED, sent },
1973 { HCBT_DESTROYWND, hook },
1974 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1975 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1976 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1977 { 0 }
1980 static const struct message WmTrackPopupMenuEmpty[] = {
1981 { HCBT_CREATEWND, hook },
1982 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1983 { WM_INITMENU, sent|lparam, 0, 0 },
1984 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1985 { 0x0093, sent|optional },
1986 { 0x0094, sent|optional },
1987 { 0x0094, sent|optional },
1988 { WM_CAPTURECHANGED, sent },
1989 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1990 { HCBT_DESTROYWND, hook },
1991 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1992 { 0 }
1995 static const struct message WmTrackPopupMenuAbort[] = {
1996 { HCBT_CREATEWND, hook },
1997 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1998 { WM_INITMENU, sent|lparam, 0, 0 },
1999 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2000 { 0x0093, sent|optional },
2001 { 0x0094, sent|optional },
2002 { 0x0094, sent|optional },
2003 { WM_CAPTURECHANGED, sent },
2004 { HCBT_DESTROYWND, hook },
2005 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2006 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2007 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2008 { 0 }
2011 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2012 static int sequence_cnt, sequence_size;
2013 static struct recvd_message* sequence;
2014 static int log_all_parent_messages;
2015 static CRITICAL_SECTION sequence_cs;
2017 /* user32 functions */
2018 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2019 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2020 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2021 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2022 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2023 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2024 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2025 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2026 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2027 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2028 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2029 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2030 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2031 /* kernel32 functions */
2032 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2034 static void init_procs(void)
2036 HMODULE user32 = GetModuleHandleA("user32.dll");
2037 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2039 #define GET_PROC(dll, func) \
2040 p ## func = (void*)GetProcAddress(dll, #func); \
2041 if(!p ## func) { \
2042 trace("GetProcAddress(%s) failed\n", #func); \
2045 GET_PROC(user32, GetAncestor)
2046 GET_PROC(user32, GetMenuInfo)
2047 GET_PROC(user32, NotifyWinEvent)
2048 GET_PROC(user32, SetMenuInfo)
2049 GET_PROC(user32, SetWinEventHook)
2050 GET_PROC(user32, TrackMouseEvent)
2051 GET_PROC(user32, UnhookWinEvent)
2052 GET_PROC(user32, GetMonitorInfoA)
2053 GET_PROC(user32, MonitorFromPoint)
2054 GET_PROC(user32, UpdateLayeredWindow)
2055 GET_PROC(user32, SetSystemTimer)
2056 GET_PROC(user32, KillSystemTimer)
2057 GET_PROC(user32, SetCoalescableTimer)
2059 GET_PROC(kernel32, GetCPInfoExA)
2061 #undef GET_PROC
2064 static const char *get_winpos_flags(UINT flags)
2066 static char buffer[300];
2068 buffer[0] = 0;
2069 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2070 DUMP( SWP_SHOWWINDOW );
2071 DUMP( SWP_HIDEWINDOW );
2072 DUMP( SWP_NOACTIVATE );
2073 DUMP( SWP_FRAMECHANGED );
2074 DUMP( SWP_NOCOPYBITS );
2075 DUMP( SWP_NOOWNERZORDER );
2076 DUMP( SWP_NOSENDCHANGING );
2077 DUMP( SWP_DEFERERASE );
2078 DUMP( SWP_ASYNCWINDOWPOS );
2079 DUMP( SWP_NOZORDER );
2080 DUMP( SWP_NOREDRAW );
2081 DUMP( SWP_NOSIZE );
2082 DUMP( SWP_NOMOVE );
2083 DUMP( SWP_NOCLIENTSIZE );
2084 DUMP( SWP_NOCLIENTMOVE );
2085 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2086 return buffer + 1;
2087 #undef DUMP
2090 static BOOL ignore_message( UINT message )
2092 /* these are always ignored */
2093 return (message >= 0xc000 ||
2094 message == WM_GETICON ||
2095 message == WM_GETOBJECT ||
2096 message == WM_TIMECHANGE ||
2097 message == WM_DISPLAYCHANGE ||
2098 message == WM_DEVICECHANGE ||
2099 message == WM_DWMNCRENDERINGCHANGED);
2103 #define add_message(msg) add_message_(__LINE__,msg);
2104 static void add_message_(int line, const struct recvd_message *msg)
2106 struct recvd_message *seq;
2108 EnterCriticalSection( &sequence_cs );
2109 if (!sequence)
2111 sequence_size = 10;
2112 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2114 if (sequence_cnt == sequence_size)
2116 sequence_size *= 2;
2117 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2119 assert(sequence);
2121 seq = &sequence[sequence_cnt++];
2122 seq->hwnd = msg->hwnd;
2123 seq->message = msg->message;
2124 seq->flags = msg->flags;
2125 seq->wParam = msg->wParam;
2126 seq->lParam = msg->lParam;
2127 seq->line = line;
2128 seq->descr = msg->descr;
2129 seq->output[0] = 0;
2130 LeaveCriticalSection( &sequence_cs );
2132 if (msg->descr)
2134 if (msg->flags & hook)
2136 static const char * const CBT_code_name[10] =
2138 "HCBT_MOVESIZE",
2139 "HCBT_MINMAX",
2140 "HCBT_QS",
2141 "HCBT_CREATEWND",
2142 "HCBT_DESTROYWND",
2143 "HCBT_ACTIVATE",
2144 "HCBT_CLICKSKIPPED",
2145 "HCBT_KEYSKIPPED",
2146 "HCBT_SYSCOMMAND",
2147 "HCBT_SETFOCUS"
2149 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2151 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2152 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2154 else if (msg->flags & winevent_hook)
2156 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2157 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2159 else
2161 switch (msg->message)
2163 case WM_WINDOWPOSCHANGING:
2164 case WM_WINDOWPOSCHANGED:
2166 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2168 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2169 msg->descr, msg->hwnd,
2170 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2171 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2172 winpos->x, winpos->y, winpos->cx, winpos->cy,
2173 get_winpos_flags(winpos->flags) );
2175 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2176 * in the high word for internal purposes
2178 seq->wParam = winpos->flags & 0xffff;
2179 /* We are not interested in the flags that don't match under XP and Win9x */
2180 seq->wParam &= ~SWP_NOZORDER;
2181 break;
2184 case WM_DRAWITEM:
2186 DRAW_ITEM_STRUCT di;
2187 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2189 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2190 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2191 dis->itemID, dis->itemAction, dis->itemState);
2193 di.u.lp = 0;
2194 di.u.item.type = dis->CtlType;
2195 di.u.item.ctl_id = dis->CtlID;
2196 if (dis->CtlType == ODT_LISTBOX ||
2197 dis->CtlType == ODT_COMBOBOX ||
2198 dis->CtlType == ODT_MENU)
2199 di.u.item.item_id = dis->itemID;
2200 di.u.item.action = dis->itemAction;
2201 di.u.item.state = dis->itemState;
2203 seq->lParam = di.u.lp;
2204 break;
2206 default:
2207 if (msg->message >= 0xc000) return; /* ignore registered messages */
2208 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2209 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2211 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2212 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2217 /* try to make sure pending X events have been processed before continuing */
2218 static void flush_events(void)
2220 MSG msg;
2221 int diff = 200;
2222 int min_timeout = 100;
2223 DWORD time = GetTickCount() + diff;
2225 while (diff > 0)
2227 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2228 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2229 diff = time - GetTickCount();
2233 static void flush_sequence(void)
2235 EnterCriticalSection( &sequence_cs );
2236 HeapFree(GetProcessHeap(), 0, sequence);
2237 sequence = 0;
2238 sequence_cnt = sequence_size = 0;
2239 LeaveCriticalSection( &sequence_cs );
2242 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2244 const struct recvd_message *actual = sequence;
2245 unsigned int count = 0;
2247 trace_(file, line)("Failed sequence %s:\n", context );
2248 while (expected->message && actual->message)
2250 if (actual->output[0])
2252 if (expected->flags & hook)
2254 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2255 count, expected->message, actual->output );
2257 else if (expected->flags & winevent_hook)
2259 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2260 count, expected->message, actual->output );
2262 else if (expected->flags & kbd_hook)
2264 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2265 count, expected->message, actual->output );
2267 else
2269 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2270 count, expected->message, actual->output );
2274 if (expected->message == actual->message)
2276 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2277 (expected->flags & optional))
2279 /* don't match messages if their defwinproc status differs */
2280 expected++;
2282 else
2284 expected++;
2285 actual++;
2288 /* silently drop winevent messages if there is no support for them */
2289 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2290 expected++;
2291 else
2293 expected++;
2294 actual++;
2296 count++;
2299 /* optional trailing messages */
2300 while (expected->message && ((expected->flags & optional) ||
2301 ((expected->flags & winevent_hook) && !hEvent_hook)))
2303 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2304 expected++;
2305 count++;
2308 if (expected->message)
2310 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2311 return;
2314 while (actual->message && actual->output[0])
2316 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2317 actual++;
2318 count++;
2322 #define ok_sequence( exp, contx, todo) \
2323 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2326 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2327 const char *file, int line)
2329 static const struct recvd_message end_of_sequence;
2330 const struct message *expected = expected_list;
2331 const struct recvd_message *actual;
2332 int failcount = 0, dump = 0;
2333 unsigned int count = 0;
2335 add_message(&end_of_sequence);
2337 actual = sequence;
2339 while (expected->message && actual->message)
2341 if (expected->message == actual->message &&
2342 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2344 if (expected->flags & wparam)
2346 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2348 todo_wine {
2349 failcount ++;
2350 if (strcmp(winetest_platform, "wine")) dump++;
2351 ok_( file, line) (FALSE,
2352 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2353 context, count, expected->message, expected->wParam, actual->wParam);
2356 else
2358 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2359 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2360 context, count, expected->message, expected->wParam, actual->wParam);
2361 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2365 if (expected->flags & lparam)
2367 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2369 todo_wine {
2370 failcount ++;
2371 if (strcmp(winetest_platform, "wine")) dump++;
2372 ok_( file, line) (FALSE,
2373 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2374 context, count, expected->message, expected->lParam, actual->lParam);
2377 else
2379 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2380 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2381 context, count, expected->message, expected->lParam, actual->lParam);
2382 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2385 if ((expected->flags & optional) &&
2386 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2388 /* don't match optional messages if their defwinproc or parent status differs */
2389 expected++;
2390 count++;
2391 continue;
2393 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2395 todo_wine {
2396 failcount ++;
2397 if (strcmp(winetest_platform, "wine")) dump++;
2398 ok_( file, line) (FALSE,
2399 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2400 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2403 else
2405 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2406 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2407 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2408 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2411 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2412 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2413 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2414 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2416 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2417 "%s: %u: the msg 0x%04x should have been %s\n",
2418 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2419 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2421 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2422 "%s: %u: the msg 0x%04x was expected in %s\n",
2423 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2424 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2426 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2427 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2428 context, count, expected->message);
2429 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2431 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2432 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2433 context, count, expected->message);
2434 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2436 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2437 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2438 context, count, expected->message);
2439 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2441 expected++;
2442 actual++;
2444 /* silently drop hook messages if there is no support for them */
2445 else if ((expected->flags & optional) ||
2446 ((expected->flags & hook) && !hCBT_hook) ||
2447 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2448 ((expected->flags & kbd_hook) && !hKBD_hook))
2449 expected++;
2450 else if (todo)
2452 failcount++;
2453 todo_wine {
2454 if (strcmp(winetest_platform, "wine")) dump++;
2455 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2456 context, count, expected->message, actual->message);
2458 goto done;
2460 else
2462 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2463 context, count, expected->message, actual->message);
2464 dump++;
2465 expected++;
2466 actual++;
2468 count++;
2471 /* skip all optional trailing messages */
2472 while (expected->message && ((expected->flags & optional) ||
2473 ((expected->flags & hook) && !hCBT_hook) ||
2474 ((expected->flags & winevent_hook) && !hEvent_hook)))
2475 expected++;
2477 if (todo)
2479 todo_wine {
2480 if (expected->message || actual->message) {
2481 failcount++;
2482 if (strcmp(winetest_platform, "wine")) dump++;
2483 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2484 context, count, expected->message, actual->message);
2488 else
2490 if (expected->message || actual->message)
2492 dump++;
2493 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2494 context, count, expected->message, actual->message);
2497 if( todo && !failcount) /* succeeded yet marked todo */
2498 todo_wine {
2499 if (!strcmp(winetest_platform, "wine")) dump++;
2500 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2503 done:
2504 if (dump) dump_sequence(expected_list, context, file, line);
2505 flush_sequence();
2508 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2510 /******************************** MDI test **********************************/
2512 /* CreateWindow for MDI frame window, initially visible */
2513 static const struct message WmCreateMDIframeSeq[] = {
2514 { HCBT_CREATEWND, hook },
2515 { WM_GETMINMAXINFO, sent },
2516 { WM_NCCREATE, sent },
2517 { WM_NCCALCSIZE, sent|wparam, 0 },
2518 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2519 { WM_CREATE, sent },
2520 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2521 { WM_NOTIFYFORMAT, sent|optional },
2522 { WM_QUERYUISTATE, sent|optional },
2523 { WM_WINDOWPOSCHANGING, sent|optional },
2524 { WM_GETMINMAXINFO, sent|optional },
2525 { WM_NCCALCSIZE, sent|optional },
2526 { WM_WINDOWPOSCHANGED, sent|optional },
2527 { WM_SHOWWINDOW, sent|wparam, 1 },
2528 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2529 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2530 { HCBT_ACTIVATE, hook },
2531 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2532 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2533 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2534 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2535 { WM_NCACTIVATE, sent },
2536 { WM_GETTEXT, sent|defwinproc|optional },
2537 { WM_ACTIVATE, sent|wparam, 1 },
2538 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2539 { HCBT_SETFOCUS, hook },
2540 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2541 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2542 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2543 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2544 /* Win9x adds SWP_NOZORDER below */
2545 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2546 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2547 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2548 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2549 { WM_MOVE, sent },
2550 { 0 }
2552 /* DestroyWindow for MDI frame window, initially visible */
2553 static const struct message WmDestroyMDIframeSeq[] = {
2554 { HCBT_DESTROYWND, hook },
2555 { 0x0090, sent|optional },
2556 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2557 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2558 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2559 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2560 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2561 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2562 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2563 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2564 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2565 { WM_DESTROY, sent },
2566 { WM_NCDESTROY, sent },
2567 { 0 }
2569 /* CreateWindow for MDI client window, initially visible */
2570 static const struct message WmCreateMDIclientSeq[] = {
2571 { HCBT_CREATEWND, hook },
2572 { WM_NCCREATE, sent },
2573 { WM_NCCALCSIZE, sent|wparam, 0 },
2574 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2575 { WM_CREATE, sent },
2576 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2577 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2578 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2579 { WM_MOVE, sent },
2580 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2581 { WM_SHOWWINDOW, sent|wparam, 1 },
2582 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2583 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2584 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2585 { 0 }
2587 /* ShowWindow(SW_SHOW) for MDI client window */
2588 static const struct message WmShowMDIclientSeq[] = {
2589 { WM_SHOWWINDOW, sent|wparam, 1 },
2590 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2591 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2592 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2593 { 0 }
2595 /* ShowWindow(SW_HIDE) for MDI client window */
2596 static const struct message WmHideMDIclientSeq[] = {
2597 { WM_SHOWWINDOW, sent|wparam, 0 },
2598 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2599 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2600 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2601 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2602 { 0 }
2604 /* DestroyWindow for MDI client window, initially visible */
2605 static const struct message WmDestroyMDIclientSeq[] = {
2606 { HCBT_DESTROYWND, hook },
2607 { 0x0090, sent|optional },
2608 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2609 { WM_SHOWWINDOW, sent|wparam, 0 },
2610 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2611 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2612 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2613 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2614 { WM_DESTROY, sent },
2615 { WM_NCDESTROY, sent },
2616 { 0 }
2618 /* CreateWindow for MDI child window, initially visible */
2619 static const struct message WmCreateMDIchildVisibleSeq[] = {
2620 { HCBT_CREATEWND, hook },
2621 { WM_NCCREATE, sent },
2622 { WM_NCCALCSIZE, sent|wparam, 0 },
2623 { WM_CREATE, sent },
2624 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2625 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2626 { WM_MOVE, sent },
2627 /* Win2k sends wparam set to
2628 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2629 * while Win9x doesn't bother to set child window id according to
2630 * CLIENTCREATESTRUCT.idFirstChild
2632 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2633 { WM_SHOWWINDOW, sent|wparam, 1 },
2634 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2635 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2636 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2637 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2638 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2639 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2640 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2642 /* Win9x: message sequence terminates here. */
2644 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2645 { HCBT_SETFOCUS, hook }, /* in MDI client */
2646 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2647 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2648 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2649 { WM_SETFOCUS, sent }, /* in MDI client */
2650 { HCBT_SETFOCUS, hook },
2651 { WM_KILLFOCUS, sent }, /* in MDI client */
2652 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2653 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2654 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2655 { WM_SETFOCUS, sent|defwinproc },
2656 { WM_MDIACTIVATE, sent|defwinproc },
2657 { 0 }
2659 /* WM_CHILDACTIVATE sent to disabled window */
2660 static const struct message WmChildActivateDisabledWindowSeq[] = {
2661 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2662 { 0 }
2664 /* WM_CHILDACTIVATE sent to enabled window */
2665 static const struct message WmChildActivateWindowSeq[] = {
2666 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2667 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2668 { WM_MDIACTIVATE, sent|defwinproc },
2669 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2670 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2671 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2672 { HCBT_SETFOCUS, hook },
2673 { WM_KILLFOCUS, sent|defwinproc },
2674 { WM_SETFOCUS, sent },
2675 { HCBT_SETFOCUS, hook },
2676 { WM_KILLFOCUS, sent },
2677 { WM_SETFOCUS, sent|defwinproc },
2678 { WM_MDIACTIVATE, sent|defwinproc },
2679 { 0 }
2681 /* CreateWindow for MDI child window with invisible parent */
2682 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2683 { HCBT_CREATEWND, hook },
2684 { WM_GETMINMAXINFO, sent },
2685 { WM_NCCREATE, sent },
2686 { WM_NCCALCSIZE, sent|wparam, 0 },
2687 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2688 { WM_CREATE, sent },
2689 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2690 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2691 { WM_MOVE, sent },
2692 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2693 { WM_SHOWWINDOW, sent|wparam, 1 },
2694 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2695 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2696 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2697 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2699 /* Win9x: message sequence terminates here. */
2701 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2702 { HCBT_SETFOCUS, hook }, /* in MDI client */
2703 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2704 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2705 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2706 { WM_SETFOCUS, sent }, /* in MDI client */
2707 { HCBT_SETFOCUS, hook },
2708 { WM_KILLFOCUS, sent }, /* in MDI client */
2709 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2710 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2711 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2712 { WM_SETFOCUS, sent|defwinproc },
2713 { WM_MDIACTIVATE, sent|defwinproc },
2714 { 0 }
2716 /* DestroyWindow for MDI child window, initially visible */
2717 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2718 { HCBT_DESTROYWND, hook },
2719 /* Win2k sends wparam set to
2720 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2721 * while Win9x doesn't bother to set child window id according to
2722 * CLIENTCREATESTRUCT.idFirstChild
2724 { 0x0090, sent|optional },
2725 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2726 { WM_SHOWWINDOW, sent|wparam, 0 },
2727 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2728 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2729 { WM_ERASEBKGND, sent|parent|optional },
2730 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2732 /* { WM_DESTROY, sent }
2733 * Win9x: message sequence terminates here.
2736 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2737 { WM_KILLFOCUS, sent },
2738 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2739 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2740 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2741 { WM_SETFOCUS, sent }, /* in MDI client */
2743 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2744 { WM_KILLFOCUS, sent }, /* in MDI client */
2745 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2746 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2747 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2748 { WM_SETFOCUS, sent }, /* in MDI client */
2750 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2752 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2753 { WM_KILLFOCUS, sent },
2754 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2755 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2756 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2757 { WM_SETFOCUS, sent }, /* in MDI client */
2759 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2760 { WM_KILLFOCUS, sent }, /* in MDI client */
2761 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2762 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2763 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2764 { WM_SETFOCUS, sent }, /* in MDI client */
2766 { WM_DESTROY, sent },
2768 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2769 { WM_KILLFOCUS, sent },
2770 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2771 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2772 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2773 { WM_SETFOCUS, sent }, /* in MDI client */
2775 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2776 { WM_KILLFOCUS, sent }, /* in MDI client */
2777 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2778 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2779 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2780 { WM_SETFOCUS, sent }, /* in MDI client */
2782 { WM_NCDESTROY, sent },
2783 { 0 }
2785 /* CreateWindow for MDI child window, initially invisible */
2786 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2787 { HCBT_CREATEWND, hook },
2788 { WM_NCCREATE, sent },
2789 { WM_NCCALCSIZE, sent|wparam, 0 },
2790 { WM_CREATE, sent },
2791 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2792 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2793 { WM_MOVE, sent },
2794 /* Win2k sends wparam set to
2795 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2796 * while Win9x doesn't bother to set child window id according to
2797 * CLIENTCREATESTRUCT.idFirstChild
2799 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2800 { 0 }
2802 /* DestroyWindow for MDI child window, initially invisible */
2803 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2804 { HCBT_DESTROYWND, hook },
2805 /* Win2k sends wparam set to
2806 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2807 * while Win9x doesn't bother to set child window id according to
2808 * CLIENTCREATESTRUCT.idFirstChild
2810 { 0x0090, sent|optional },
2811 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2812 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2813 { WM_DESTROY, sent },
2814 { WM_NCDESTROY, sent },
2815 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2816 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2817 { 0 }
2819 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2820 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2821 { HCBT_CREATEWND, hook },
2822 { WM_NCCREATE, sent },
2823 { WM_NCCALCSIZE, sent|wparam, 0 },
2824 { WM_CREATE, sent },
2825 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2826 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2827 { WM_MOVE, sent },
2828 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2829 { WM_GETMINMAXINFO, sent },
2830 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2831 { WM_NCCALCSIZE, sent|wparam, 1 },
2832 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2833 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2834 /* in MDI frame */
2835 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2836 { WM_NCCALCSIZE, sent|wparam, 1 },
2837 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2838 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2839 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2840 /* Win2k sends wparam set to
2841 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2842 * while Win9x doesn't bother to set child window id according to
2843 * CLIENTCREATESTRUCT.idFirstChild
2845 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2846 { WM_SHOWWINDOW, sent|wparam, 1 },
2847 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2848 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2849 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2850 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2851 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2852 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2853 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2855 /* Win9x: message sequence terminates here. */
2857 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2858 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2859 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2860 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2861 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2862 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2863 { HCBT_SETFOCUS, hook|optional },
2864 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2865 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2866 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2867 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2868 { WM_SETFOCUS, sent|defwinproc|optional },
2869 { WM_MDIACTIVATE, sent|defwinproc|optional },
2870 /* in MDI frame */
2871 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2872 { WM_NCCALCSIZE, sent|wparam, 1 },
2873 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2874 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2875 { 0 }
2877 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2878 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2879 /* restore the 1st MDI child */
2880 { WM_SETREDRAW, sent|wparam, 0 },
2881 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2882 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2883 { WM_NCCALCSIZE, sent|wparam, 1 },
2884 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2885 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2886 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2887 /* in MDI frame */
2888 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2889 { WM_NCCALCSIZE, sent|wparam, 1 },
2890 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2891 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2892 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2893 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2894 /* create the 2nd MDI child */
2895 { HCBT_CREATEWND, hook },
2896 { WM_NCCREATE, sent },
2897 { WM_NCCALCSIZE, sent|wparam, 0 },
2898 { WM_CREATE, sent },
2899 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2900 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2901 { WM_MOVE, sent },
2902 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2903 { WM_GETMINMAXINFO, sent },
2904 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2905 { WM_NCCALCSIZE, sent|wparam, 1 },
2906 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2907 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2908 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2909 /* in MDI frame */
2910 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2911 { WM_NCCALCSIZE, sent|wparam, 1 },
2912 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2913 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2914 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2915 /* Win2k sends wparam set to
2916 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2917 * while Win9x doesn't bother to set child window id according to
2918 * CLIENTCREATESTRUCT.idFirstChild
2920 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2921 { WM_SHOWWINDOW, sent|wparam, 1 },
2922 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2923 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2924 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2925 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2926 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2927 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2929 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2930 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2932 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2934 /* Win9x: message sequence terminates here. */
2936 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2937 { HCBT_SETFOCUS, hook },
2938 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2939 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2940 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2941 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2942 { WM_SETFOCUS, sent }, /* in MDI client */
2943 { HCBT_SETFOCUS, hook },
2944 { WM_KILLFOCUS, sent }, /* in MDI client */
2945 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2946 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2947 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2948 { WM_SETFOCUS, sent|defwinproc },
2950 { WM_MDIACTIVATE, sent|defwinproc },
2951 /* in MDI frame */
2952 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2953 { WM_NCCALCSIZE, sent|wparam, 1 },
2954 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2955 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2956 { 0 }
2958 /* WM_MDICREATE MDI child window, initially visible and maximized */
2959 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2960 { WM_MDICREATE, sent },
2961 { HCBT_CREATEWND, hook },
2962 { WM_NCCREATE, sent },
2963 { WM_NCCALCSIZE, sent|wparam, 0 },
2964 { WM_CREATE, sent },
2965 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2966 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2967 { WM_MOVE, sent },
2968 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2969 { WM_GETMINMAXINFO, sent },
2970 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2971 { WM_NCCALCSIZE, sent|wparam, 1 },
2972 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2973 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2975 /* in MDI frame */
2976 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2977 { WM_NCCALCSIZE, sent|wparam, 1 },
2978 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2979 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2980 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2982 /* Win2k sends wparam set to
2983 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2984 * while Win9x doesn't bother to set child window id according to
2985 * CLIENTCREATESTRUCT.idFirstChild
2987 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2988 { WM_SHOWWINDOW, sent|wparam, 1 },
2989 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2991 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2993 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2994 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2995 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2997 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2998 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3000 /* Win9x: message sequence terminates here. */
3002 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3003 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3004 { HCBT_SETFOCUS, hook }, /* in MDI client */
3005 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3006 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3007 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3008 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3009 { HCBT_SETFOCUS, hook|optional },
3010 { WM_KILLFOCUS, sent }, /* in MDI client */
3011 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3012 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3013 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3014 { WM_SETFOCUS, sent|defwinproc },
3016 { WM_MDIACTIVATE, sent|defwinproc },
3018 /* in MDI child */
3019 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3020 { WM_NCCALCSIZE, sent|wparam, 1 },
3021 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3022 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3024 /* in MDI frame */
3025 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3026 { WM_NCCALCSIZE, sent|wparam, 1 },
3027 { 0x0093, sent|defwinproc|optional },
3028 { 0x0093, sent|defwinproc|optional },
3029 { 0x0093, sent|defwinproc|optional },
3030 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3031 { WM_MOVE, sent|defwinproc },
3032 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3034 /* in MDI client */
3035 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3036 { WM_NCCALCSIZE, sent|wparam, 1 },
3037 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3038 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3040 /* in MDI child */
3041 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3042 { WM_NCCALCSIZE, sent|wparam, 1 },
3043 { 0x0093, sent|optional },
3044 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3045 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3047 { 0x0093, sent|optional },
3048 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3049 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3050 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3051 { 0x0093, sent|defwinproc|optional },
3052 { 0x0093, sent|defwinproc|optional },
3053 { 0x0093, sent|defwinproc|optional },
3054 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3055 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3057 { 0 }
3059 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3060 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3061 { HCBT_CREATEWND, hook },
3062 { WM_GETMINMAXINFO, sent },
3063 { WM_NCCREATE, sent },
3064 { WM_NCCALCSIZE, sent|wparam, 0 },
3065 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3066 { WM_CREATE, sent },
3067 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3068 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3069 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3070 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3071 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3072 { WM_MOVE, sent },
3073 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3074 { WM_GETMINMAXINFO, sent },
3075 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3076 { WM_GETMINMAXINFO, sent|defwinproc },
3077 { WM_NCCALCSIZE, sent|wparam, 1 },
3078 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3079 { WM_MOVE, sent|defwinproc },
3080 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3081 /* in MDI frame */
3082 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3083 { WM_NCCALCSIZE, sent|wparam, 1 },
3084 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3085 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3086 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3087 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3088 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3089 /* Win2k sends wparam set to
3090 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3091 * while Win9x doesn't bother to set child window id according to
3092 * CLIENTCREATESTRUCT.idFirstChild
3094 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3095 { 0 }
3097 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3098 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3099 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3100 { HCBT_SYSCOMMAND, hook },
3101 { WM_CLOSE, sent|defwinproc },
3102 { WM_MDIDESTROY, sent }, /* in MDI client */
3104 /* bring the 1st MDI child to top */
3105 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3106 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3108 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3110 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3111 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3112 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3114 /* maximize the 1st MDI child */
3115 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3116 { WM_GETMINMAXINFO, sent|defwinproc },
3117 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3118 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3119 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3120 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3121 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3123 /* restore the 2nd MDI child */
3124 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3125 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3126 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3127 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3129 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3131 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3132 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3134 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3136 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3137 /* in MDI frame */
3138 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3139 { WM_NCCALCSIZE, sent|wparam, 1 },
3140 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3141 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3142 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3144 /* bring the 1st MDI child to top */
3145 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3146 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3147 { HCBT_SETFOCUS, hook },
3148 { WM_KILLFOCUS, sent|defwinproc },
3149 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3150 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3151 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3152 { WM_SETFOCUS, sent }, /* in MDI client */
3153 { HCBT_SETFOCUS, hook },
3154 { WM_KILLFOCUS, sent }, /* in MDI client */
3155 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3156 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3157 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3158 { WM_SETFOCUS, sent|defwinproc },
3159 { WM_MDIACTIVATE, sent|defwinproc },
3160 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3162 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3163 { WM_SHOWWINDOW, sent|wparam, 1 },
3164 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3165 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3166 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3167 { WM_MDIREFRESHMENU, sent },
3169 { HCBT_DESTROYWND, hook },
3170 /* Win2k sends wparam set to
3171 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3172 * while Win9x doesn't bother to set child window id according to
3173 * CLIENTCREATESTRUCT.idFirstChild
3175 { 0x0090, sent|defwinproc|optional },
3176 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3177 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3178 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3179 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3180 { WM_ERASEBKGND, sent|parent|optional },
3181 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3183 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3184 { WM_DESTROY, sent|defwinproc },
3185 { WM_NCDESTROY, sent|defwinproc },
3186 { 0 }
3188 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3189 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3190 { WM_MDIDESTROY, sent }, /* in MDI client */
3191 { WM_SHOWWINDOW, sent|wparam, 0 },
3192 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3193 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3194 { WM_ERASEBKGND, sent|parent|optional },
3195 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3197 { HCBT_SETFOCUS, hook },
3198 { WM_KILLFOCUS, sent },
3199 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3200 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3201 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3202 { WM_SETFOCUS, sent }, /* in MDI client */
3203 { HCBT_SETFOCUS, hook },
3204 { WM_KILLFOCUS, sent }, /* in MDI client */
3205 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3206 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3207 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3208 { WM_SETFOCUS, sent },
3210 /* in MDI child */
3211 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3212 { WM_NCCALCSIZE, sent|wparam, 1 },
3213 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3214 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3216 /* in MDI frame */
3217 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3218 { WM_NCCALCSIZE, sent|wparam, 1 },
3219 { 0x0093, sent|defwinproc|optional },
3220 { 0x0093, sent|defwinproc|optional },
3221 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3222 { WM_MOVE, sent|defwinproc },
3223 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3225 /* in MDI client */
3226 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3227 { WM_NCCALCSIZE, sent|wparam, 1 },
3228 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3229 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3231 /* in MDI child */
3232 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3233 { WM_NCCALCSIZE, sent|wparam, 1 },
3234 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3235 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3237 /* in MDI child */
3238 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3239 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3240 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3241 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3243 /* in MDI frame */
3244 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3245 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3246 { 0x0093, sent|defwinproc|optional },
3247 { 0x0093, sent|defwinproc|optional },
3248 { 0x0093, sent|defwinproc|optional },
3249 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3250 { WM_MOVE, sent|defwinproc },
3251 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3253 /* in MDI client */
3254 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3255 { WM_NCCALCSIZE, sent|wparam, 1 },
3256 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3257 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3259 /* in MDI child */
3260 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3261 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3262 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3263 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3264 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3265 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3267 { 0x0093, sent|defwinproc|optional },
3268 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3269 { 0x0093, sent|defwinproc|optional },
3270 { 0x0093, sent|defwinproc|optional },
3271 { 0x0093, sent|defwinproc|optional },
3272 { 0x0093, sent|optional },
3274 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3275 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3276 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3277 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3278 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3280 /* in MDI frame */
3281 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3282 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3283 { 0x0093, sent|defwinproc|optional },
3284 { 0x0093, sent|defwinproc|optional },
3285 { 0x0093, sent|defwinproc|optional },
3286 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3287 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3288 { 0x0093, sent|optional },
3290 { WM_NCACTIVATE, sent|wparam, 0 },
3291 { WM_MDIACTIVATE, sent },
3293 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3294 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3295 { WM_NCCALCSIZE, sent|wparam, 1 },
3297 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3299 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3300 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3301 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3303 /* in MDI child */
3304 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3305 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3306 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3307 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3309 /* in MDI frame */
3310 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3311 { WM_NCCALCSIZE, sent|wparam, 1 },
3312 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3313 { WM_MOVE, sent|defwinproc },
3314 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3316 /* in MDI client */
3317 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3318 { WM_NCCALCSIZE, sent|wparam, 1 },
3319 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3320 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3321 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3322 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3323 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3324 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3325 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3327 { HCBT_SETFOCUS, hook },
3328 { WM_KILLFOCUS, sent },
3329 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3330 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3331 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3332 { WM_SETFOCUS, sent }, /* in MDI client */
3334 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3336 { HCBT_DESTROYWND, hook },
3337 /* Win2k sends wparam set to
3338 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3339 * while Win9x doesn't bother to set child window id according to
3340 * CLIENTCREATESTRUCT.idFirstChild
3342 { 0x0090, sent|optional },
3343 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3345 { WM_SHOWWINDOW, sent|wparam, 0 },
3346 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3347 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3348 { WM_ERASEBKGND, sent|parent|optional },
3349 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3351 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3352 { WM_DESTROY, sent },
3353 { WM_NCDESTROY, sent },
3354 { 0 }
3356 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3357 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3358 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3359 { WM_GETMINMAXINFO, sent },
3360 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3361 { WM_NCCALCSIZE, sent|wparam, 1 },
3362 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3363 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3365 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3366 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3367 { HCBT_SETFOCUS, hook|optional },
3368 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3369 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3370 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3371 { HCBT_SETFOCUS, hook|optional },
3372 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3373 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3374 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3375 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3376 { WM_SETFOCUS, sent|optional|defwinproc },
3377 { WM_MDIACTIVATE, sent|optional|defwinproc },
3378 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3379 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3380 /* in MDI frame */
3381 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3382 { WM_NCCALCSIZE, sent|wparam, 1 },
3383 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3384 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3385 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3386 { 0 }
3388 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3389 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3390 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3391 { WM_GETMINMAXINFO, sent },
3392 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3393 { WM_GETMINMAXINFO, sent|defwinproc },
3394 { WM_NCCALCSIZE, sent|wparam, 1 },
3395 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3396 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3398 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3399 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3400 { HCBT_SETFOCUS, hook|optional },
3401 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3402 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3403 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3404 { HCBT_SETFOCUS, hook|optional },
3405 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3406 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3407 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3408 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3409 { WM_SETFOCUS, sent|defwinproc|optional },
3410 { WM_MDIACTIVATE, sent|defwinproc|optional },
3411 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3412 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3413 { 0 }
3415 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3416 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3417 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3418 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3419 { WM_GETMINMAXINFO, sent },
3420 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3421 { WM_GETMINMAXINFO, sent|defwinproc },
3422 { WM_NCCALCSIZE, sent|wparam, 1 },
3423 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3424 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3425 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3426 { WM_MOVE, sent|defwinproc },
3427 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3429 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3430 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3431 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3432 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3433 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3434 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3435 /* in MDI frame */
3436 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3437 { WM_NCCALCSIZE, sent|wparam, 1 },
3438 { 0x0093, sent|defwinproc|optional },
3439 { 0x0094, sent|defwinproc|optional },
3440 { 0x0094, sent|defwinproc|optional },
3441 { 0x0094, sent|defwinproc|optional },
3442 { 0x0094, sent|defwinproc|optional },
3443 { 0x0093, sent|defwinproc|optional },
3444 { 0x0093, sent|defwinproc|optional },
3445 { 0x0091, sent|defwinproc|optional },
3446 { 0x0092, sent|defwinproc|optional },
3447 { 0x0092, sent|defwinproc|optional },
3448 { 0x0092, sent|defwinproc|optional },
3449 { 0x0092, sent|defwinproc|optional },
3450 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3451 { WM_MOVE, sent|defwinproc },
3452 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3453 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3454 /* in MDI client */
3455 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3456 { WM_NCCALCSIZE, sent|wparam, 1 },
3457 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3458 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3459 /* in MDI child */
3460 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3461 { WM_GETMINMAXINFO, sent|defwinproc },
3462 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3463 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3464 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3465 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3466 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3467 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3468 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3469 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3470 /* in MDI frame */
3471 { 0x0093, sent|optional },
3472 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3473 { 0x0093, sent|defwinproc|optional },
3474 { 0x0093, sent|defwinproc|optional },
3475 { 0x0093, sent|defwinproc|optional },
3476 { 0x0091, sent|defwinproc|optional },
3477 { 0x0092, sent|defwinproc|optional },
3478 { 0x0092, sent|defwinproc|optional },
3479 { 0x0092, sent|defwinproc|optional },
3480 { 0x0092, sent|defwinproc|optional },
3481 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3482 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3483 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3484 { 0 }
3486 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3487 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3488 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3489 { WM_GETMINMAXINFO, sent },
3490 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3491 { WM_NCCALCSIZE, sent|wparam, 1 },
3492 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3493 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3494 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3495 /* in MDI frame */
3496 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3497 { WM_NCCALCSIZE, sent|wparam, 1 },
3498 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3499 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3500 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3501 { 0 }
3503 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3504 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3505 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3506 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3507 { WM_NCCALCSIZE, sent|wparam, 1 },
3508 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3509 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3510 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3511 /* in MDI frame */
3512 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3513 { WM_NCCALCSIZE, sent|wparam, 1 },
3514 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3515 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3516 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3517 { 0 }
3519 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3520 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3521 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3522 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3523 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3524 { WM_NCCALCSIZE, sent|wparam, 1 },
3525 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3526 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3527 { WM_MOVE, sent|defwinproc },
3528 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3529 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3530 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3531 { HCBT_SETFOCUS, hook },
3532 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3533 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3534 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3535 { WM_SETFOCUS, sent },
3536 { 0 }
3538 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3539 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3540 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3541 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3542 { WM_NCCALCSIZE, sent|wparam, 1 },
3543 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3544 { WM_MOVE, sent|defwinproc },
3545 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3546 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3547 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3548 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3549 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3550 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3551 { 0 }
3553 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3554 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3555 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3556 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3557 { WM_NCCALCSIZE, sent|wparam, 1 },
3558 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3559 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3560 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3561 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3562 /* in MDI frame */
3563 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3564 { WM_NCCALCSIZE, sent|wparam, 1 },
3565 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3566 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3567 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3568 { 0 }
3571 static HWND mdi_client;
3572 static WNDPROC old_mdi_client_proc;
3574 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3576 struct recvd_message msg;
3578 /* do not log painting messages */
3579 if (message != WM_PAINT &&
3580 message != WM_NCPAINT &&
3581 message != WM_SYNCPAINT &&
3582 message != WM_ERASEBKGND &&
3583 message != WM_NCHITTEST &&
3584 message != WM_GETTEXT &&
3585 message != WM_MDIGETACTIVE &&
3586 !ignore_message( message ))
3588 msg.hwnd = hwnd;
3589 msg.message = message;
3590 msg.flags = sent|wparam|lparam;
3591 msg.wParam = wParam;
3592 msg.lParam = lParam;
3593 msg.descr = "mdi client";
3594 add_message(&msg);
3597 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3600 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3602 static LONG defwndproc_counter = 0;
3603 LRESULT ret;
3604 struct recvd_message msg;
3606 /* do not log painting messages */
3607 if (message != WM_PAINT &&
3608 message != WM_NCPAINT &&
3609 message != WM_SYNCPAINT &&
3610 message != WM_ERASEBKGND &&
3611 message != WM_NCHITTEST &&
3612 message != WM_GETTEXT &&
3613 !ignore_message( message ))
3615 switch (message)
3617 case WM_MDIACTIVATE:
3619 HWND active, client = GetParent(hwnd);
3621 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3623 if (hwnd == (HWND)lParam) /* if we are being activated */
3624 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3625 else
3626 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3627 break;
3631 msg.hwnd = hwnd;
3632 msg.message = message;
3633 msg.flags = sent|wparam|lparam;
3634 if (defwndproc_counter) msg.flags |= defwinproc;
3635 msg.wParam = wParam;
3636 msg.lParam = lParam;
3637 msg.descr = "mdi child";
3638 add_message(&msg);
3641 defwndproc_counter++;
3642 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3643 defwndproc_counter--;
3645 return ret;
3648 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3650 static LONG defwndproc_counter = 0;
3651 LRESULT ret;
3652 struct recvd_message msg;
3654 /* do not log painting messages */
3655 if (message != WM_PAINT &&
3656 message != WM_NCPAINT &&
3657 message != WM_SYNCPAINT &&
3658 message != WM_ERASEBKGND &&
3659 message != WM_NCHITTEST &&
3660 message != WM_GETTEXT &&
3661 !ignore_message( message ))
3663 msg.hwnd = hwnd;
3664 msg.message = message;
3665 msg.flags = sent|wparam|lparam;
3666 if (defwndproc_counter) msg.flags |= defwinproc;
3667 msg.wParam = wParam;
3668 msg.lParam = lParam;
3669 msg.descr = "mdi frame";
3670 add_message(&msg);
3673 defwndproc_counter++;
3674 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3675 defwndproc_counter--;
3677 return ret;
3680 static BOOL mdi_RegisterWindowClasses(void)
3682 WNDCLASSA cls;
3684 cls.style = 0;
3685 cls.lpfnWndProc = mdi_frame_wnd_proc;
3686 cls.cbClsExtra = 0;
3687 cls.cbWndExtra = 0;
3688 cls.hInstance = GetModuleHandleA(0);
3689 cls.hIcon = 0;
3690 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3691 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3692 cls.lpszMenuName = NULL;
3693 cls.lpszClassName = "MDI_frame_class";
3694 if (!RegisterClassA(&cls)) return FALSE;
3696 cls.lpfnWndProc = mdi_child_wnd_proc;
3697 cls.lpszClassName = "MDI_child_class";
3698 if (!RegisterClassA(&cls)) return FALSE;
3700 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3701 old_mdi_client_proc = cls.lpfnWndProc;
3702 cls.hInstance = GetModuleHandleA(0);
3703 cls.lpfnWndProc = mdi_client_hook_proc;
3704 cls.lpszClassName = "MDI_client_class";
3705 if (!RegisterClassA(&cls)) assert(0);
3707 return TRUE;
3710 static void test_mdi_messages(void)
3712 MDICREATESTRUCTA mdi_cs;
3713 CLIENTCREATESTRUCT client_cs;
3714 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3715 BOOL zoomed;
3716 RECT rc;
3717 HMENU hMenu = CreateMenu();
3718 LONG val;
3720 if (!mdi_RegisterWindowClasses()) assert(0);
3722 flush_sequence();
3724 trace("creating MDI frame window\n");
3725 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3726 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3727 WS_MAXIMIZEBOX | WS_VISIBLE,
3728 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3729 GetDesktopWindow(), hMenu,
3730 GetModuleHandleA(0), NULL);
3731 assert(mdi_frame);
3732 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3734 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3735 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3737 trace("creating MDI client window\n");
3738 GetClientRect(mdi_frame, &rc);
3739 client_cs.hWindowMenu = 0;
3740 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3741 mdi_client = CreateWindowExA(0, "MDI_client_class",
3742 NULL,
3743 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3744 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3745 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3746 assert(mdi_client);
3747 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3749 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3750 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3751 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3753 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3754 ok(!active_child, "wrong active MDI child %p\n", active_child);
3755 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3757 SetFocus(0);
3758 flush_sequence();
3760 trace("creating invisible MDI child window\n");
3761 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3762 WS_CHILD,
3763 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3764 mdi_client, 0, GetModuleHandleA(0), NULL);
3765 assert(mdi_child);
3767 flush_sequence();
3768 ShowWindow(mdi_child, SW_SHOWNORMAL);
3769 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3771 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3772 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3774 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3775 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3777 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3778 ok(!active_child, "wrong active MDI child %p\n", active_child);
3779 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3781 ShowWindow(mdi_child, SW_HIDE);
3782 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3783 flush_sequence();
3785 ShowWindow(mdi_child, SW_SHOW);
3786 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3788 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3789 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3791 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3792 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3794 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3795 ok(!active_child, "wrong active MDI child %p\n", active_child);
3796 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3798 DestroyWindow(mdi_child);
3799 flush_sequence();
3801 trace("creating visible MDI child window\n");
3802 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3803 WS_CHILD | WS_VISIBLE,
3804 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3805 mdi_client, 0, GetModuleHandleA(0), NULL);
3806 assert(mdi_child);
3807 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3809 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3810 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3812 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3813 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3815 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3816 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3817 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3818 flush_sequence();
3820 DestroyWindow(mdi_child);
3821 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3823 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3824 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3826 /* Win2k: MDI client still returns a just destroyed child as active
3827 * Win9x: MDI client returns 0
3829 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3830 ok(active_child == mdi_child || /* win2k */
3831 !active_child, /* win9x */
3832 "wrong active MDI child %p\n", active_child);
3833 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3835 flush_sequence();
3837 trace("creating invisible MDI child window\n");
3838 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3839 WS_CHILD,
3840 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3841 mdi_client, 0, GetModuleHandleA(0), NULL);
3842 assert(mdi_child2);
3843 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3845 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3846 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3848 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3849 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3851 /* Win2k: MDI client still returns a just destroyed child as active
3852 * Win9x: MDI client returns mdi_child2
3854 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3855 ok(active_child == mdi_child || /* win2k */
3856 active_child == mdi_child2, /* win9x */
3857 "wrong active MDI child %p\n", active_child);
3858 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3859 flush_sequence();
3861 ShowWindow(mdi_child2, SW_MAXIMIZE);
3862 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3864 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3865 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3867 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3868 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3869 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3870 flush_sequence();
3872 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3873 ok(GetFocus() == mdi_child2 || /* win2k */
3874 GetFocus() == 0, /* win9x */
3875 "wrong focus window %p\n", GetFocus());
3877 SetFocus(0);
3878 flush_sequence();
3880 ShowWindow(mdi_child2, SW_HIDE);
3881 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3883 ShowWindow(mdi_child2, SW_RESTORE);
3884 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3885 flush_sequence();
3887 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3888 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3890 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3891 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3892 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3893 flush_sequence();
3895 SetFocus(0);
3896 flush_sequence();
3898 ShowWindow(mdi_child2, SW_HIDE);
3899 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3901 ShowWindow(mdi_child2, SW_SHOW);
3902 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3904 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3905 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3907 ShowWindow(mdi_child2, SW_MAXIMIZE);
3908 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3910 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3911 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3913 ShowWindow(mdi_child2, SW_RESTORE);
3914 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3916 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3917 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3919 ShowWindow(mdi_child2, SW_MINIMIZE);
3920 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3922 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3923 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3925 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3926 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3927 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3928 flush_sequence();
3930 ShowWindow(mdi_child2, SW_RESTORE);
3931 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3933 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3934 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3936 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3937 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3938 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3939 flush_sequence();
3941 SetFocus(0);
3942 flush_sequence();
3944 ShowWindow(mdi_child2, SW_HIDE);
3945 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3947 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3948 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3950 DestroyWindow(mdi_child2);
3951 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3953 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3954 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3956 trace("Testing WM_CHILDACTIVATE\n");
3958 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3959 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
3960 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3961 mdi_client, 0, GetModuleHandleA(0), NULL);
3963 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3964 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
3965 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3966 mdi_client, 0, GetModuleHandleA(0), NULL);
3968 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3969 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3970 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3972 flush_sequence();
3973 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
3974 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
3976 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3977 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3978 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3979 flush_sequence();
3981 EnableWindow(mdi_child, TRUE);
3983 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3984 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3985 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3987 flush_sequence();
3988 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
3989 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
3991 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3992 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3993 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3994 flush_sequence();
3996 DestroyWindow(mdi_child);
3997 DestroyWindow(mdi_child2);
3998 flush_sequence();
4000 /* test for maximized MDI children */
4001 trace("creating maximized visible MDI child window 1\n");
4002 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4003 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4004 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4005 mdi_client, 0, GetModuleHandleA(0), NULL);
4006 assert(mdi_child);
4007 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4008 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4010 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4011 ok(GetFocus() == mdi_child || /* win2k */
4012 GetFocus() == 0, /* win9x */
4013 "wrong focus window %p\n", GetFocus());
4015 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4016 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4017 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4018 flush_sequence();
4020 trace("creating maximized visible MDI child window 2\n");
4021 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4022 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4023 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4024 mdi_client, 0, GetModuleHandleA(0), NULL);
4025 assert(mdi_child2);
4026 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4027 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4028 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4030 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4031 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4033 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4034 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4035 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4036 flush_sequence();
4038 trace("destroying maximized visible MDI child window 2\n");
4039 DestroyWindow(mdi_child2);
4040 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4042 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4044 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4045 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4047 /* Win2k: MDI client still returns a just destroyed child as active
4048 * Win9x: MDI client returns 0
4050 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4051 ok(active_child == mdi_child2 || /* win2k */
4052 !active_child, /* win9x */
4053 "wrong active MDI child %p\n", active_child);
4054 flush_sequence();
4056 ShowWindow(mdi_child, SW_MAXIMIZE);
4057 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4058 flush_sequence();
4060 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4061 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4063 trace("re-creating maximized visible MDI child window 2\n");
4064 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4065 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4066 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4067 mdi_client, 0, GetModuleHandleA(0), NULL);
4068 assert(mdi_child2);
4069 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4070 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4071 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4073 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4074 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4076 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4077 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4078 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4079 flush_sequence();
4081 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4082 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4083 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4085 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4086 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4087 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4089 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4090 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4091 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4092 flush_sequence();
4094 DestroyWindow(mdi_child);
4095 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4097 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4098 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4100 /* Win2k: MDI client still returns a just destroyed child as active
4101 * Win9x: MDI client returns 0
4103 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4104 ok(active_child == mdi_child || /* win2k */
4105 !active_child, /* win9x */
4106 "wrong active MDI child %p\n", active_child);
4107 flush_sequence();
4109 trace("creating maximized invisible MDI child window\n");
4110 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4111 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4112 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4113 mdi_client, 0, GetModuleHandleA(0), NULL);
4114 assert(mdi_child2);
4115 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4116 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4117 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4118 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4120 /* Win2k: MDI client still returns a just destroyed child as active
4121 * Win9x: MDI client returns 0
4123 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4124 ok(active_child == mdi_child || /* win2k */
4125 !active_child || active_child == mdi_child2, /* win9x */
4126 "wrong active MDI child %p\n", active_child);
4127 flush_sequence();
4129 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4130 ShowWindow(mdi_child2, SW_MAXIMIZE);
4131 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4132 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4133 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4134 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4136 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4137 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4138 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4139 flush_sequence();
4141 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4142 flush_sequence();
4144 /* end of test for maximized MDI children */
4145 SetFocus(0);
4146 flush_sequence();
4147 trace("creating maximized visible MDI child window 1(Switch test)\n");
4148 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4149 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4150 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4151 mdi_client, 0, GetModuleHandleA(0), NULL);
4152 assert(mdi_child);
4153 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4154 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4156 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4157 ok(GetFocus() == mdi_child || /* win2k */
4158 GetFocus() == 0, /* win9x */
4159 "wrong focus window %p(Switch test)\n", GetFocus());
4161 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4162 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4163 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4164 flush_sequence();
4166 trace("creating maximized visible MDI child window 2(Switch test)\n");
4167 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4168 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4169 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4170 mdi_client, 0, GetModuleHandleA(0), NULL);
4171 assert(mdi_child2);
4172 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4174 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4175 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4177 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4178 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4180 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4181 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4182 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4183 flush_sequence();
4185 trace("Switch child window.\n");
4186 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4187 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4188 trace("end of test for switch maximized MDI children\n");
4189 flush_sequence();
4191 /* Prepare for switching test of not maximized MDI children */
4192 ShowWindow( mdi_child, SW_NORMAL );
4193 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4194 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4195 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4196 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4197 flush_sequence();
4199 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4200 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4201 trace("end of test for switch not maximized MDI children\n");
4202 flush_sequence();
4204 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4205 flush_sequence();
4207 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4208 flush_sequence();
4210 SetFocus(0);
4211 flush_sequence();
4212 /* end of tests for switch maximized/not maximized MDI children */
4214 mdi_cs.szClass = "MDI_child_Class";
4215 mdi_cs.szTitle = "MDI child";
4216 mdi_cs.hOwner = GetModuleHandleA(0);
4217 mdi_cs.x = 0;
4218 mdi_cs.y = 0;
4219 mdi_cs.cx = CW_USEDEFAULT;
4220 mdi_cs.cy = CW_USEDEFAULT;
4221 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4222 mdi_cs.lParam = 0;
4223 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4224 ok(mdi_child != 0, "MDI child creation failed\n");
4225 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4227 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4229 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4230 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4232 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4233 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4234 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4236 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4237 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4238 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4239 flush_sequence();
4241 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4242 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4244 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4245 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4246 ok(!active_child, "wrong active MDI child %p\n", active_child);
4248 SetFocus(0);
4249 flush_sequence();
4251 val = GetWindowLongA(mdi_client, 0);
4252 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4253 DestroyWindow(mdi_client);
4254 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4256 /* test maximization of MDI child with invisible parent */
4257 client_cs.hWindowMenu = 0;
4258 mdi_client = CreateWindowA("MDI_client_class",
4259 NULL,
4260 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4261 0, 0, 660, 430,
4262 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4263 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4265 ShowWindow(mdi_client, SW_HIDE);
4266 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4268 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4269 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4270 0, 0, 650, 440,
4271 mdi_client, 0, GetModuleHandleA(0), NULL);
4272 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4274 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4275 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4276 zoomed = IsZoomed(mdi_child);
4277 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4279 ShowWindow(mdi_client, SW_SHOW);
4280 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4282 DestroyWindow(mdi_child);
4283 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4285 /* end of test for maximization of MDI child with invisible parent */
4287 DestroyWindow(mdi_client);
4288 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4290 DestroyWindow(mdi_frame);
4291 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4293 /************************* End of MDI test **********************************/
4295 static void test_WM_SETREDRAW(HWND hwnd)
4297 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4299 flush_events();
4300 flush_sequence();
4302 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4303 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4305 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4306 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4308 flush_sequence();
4309 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4310 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4312 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4313 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4315 /* restore original WS_VISIBLE state */
4316 SetWindowLongA(hwnd, GWL_STYLE, style);
4318 flush_events();
4319 flush_sequence();
4322 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4324 struct recvd_message msg;
4326 if (ignore_message( message )) return 0;
4328 switch (message)
4330 /* ignore */
4331 case WM_MOUSEMOVE:
4332 case WM_NCMOUSEMOVE:
4333 case WM_NCMOUSELEAVE:
4334 case WM_SETCURSOR:
4335 return 0;
4336 case WM_NCHITTEST:
4337 return HTCLIENT;
4340 msg.hwnd = hwnd;
4341 msg.message = message;
4342 msg.flags = sent|wparam|lparam;
4343 msg.wParam = wParam;
4344 msg.lParam = lParam;
4345 msg.descr = "dialog";
4346 add_message(&msg);
4348 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4349 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4350 return 0;
4353 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4355 struct recvd_message msg;
4357 if (ignore_message( message )) return 0;
4359 switch (message)
4361 /* ignore */
4362 case WM_MOUSEMOVE:
4363 case WM_NCMOUSEMOVE:
4364 case WM_NCMOUSELEAVE:
4365 case WM_SETCURSOR:
4366 return 0;
4367 case WM_NCHITTEST:
4368 return HTCLIENT;
4371 msg.hwnd = hwnd;
4372 msg.message = message;
4373 msg.flags = sent|wparam|lparam;
4374 msg.wParam = wParam;
4375 msg.lParam = lParam;
4376 msg.descr = "dialog";
4377 add_message(&msg);
4379 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4380 return 0;
4383 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4385 DWORD style, exstyle;
4386 INT xmin, xmax;
4387 BOOL ret;
4389 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4390 style = GetWindowLongA(hwnd, GWL_STYLE);
4391 /* do not be confused by WS_DLGFRAME set */
4392 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4394 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4395 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4397 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4398 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4399 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4400 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4401 else
4402 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4404 style = GetWindowLongA(hwnd, GWL_STYLE);
4405 if (set) ok(style & set, "style %08x should be set\n", set);
4406 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4408 /* a subsequent call should do nothing */
4409 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4410 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4411 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4413 xmin = 0xdeadbeef;
4414 xmax = 0xdeadbeef;
4415 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4416 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4417 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4418 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4419 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4422 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4424 DWORD style, exstyle;
4425 SCROLLINFO si;
4426 BOOL ret;
4428 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4429 style = GetWindowLongA(hwnd, GWL_STYLE);
4430 /* do not be confused by WS_DLGFRAME set */
4431 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4433 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4434 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4436 si.cbSize = sizeof(si);
4437 si.fMask = SIF_RANGE;
4438 si.nMin = min;
4439 si.nMax = max;
4440 SetScrollInfo(hwnd, ctl, &si, TRUE);
4441 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4442 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4443 else
4444 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4446 style = GetWindowLongA(hwnd, GWL_STYLE);
4447 if (set) ok(style & set, "style %08x should be set\n", set);
4448 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4450 /* a subsequent call should do nothing */
4451 SetScrollInfo(hwnd, ctl, &si, TRUE);
4452 if (style & WS_HSCROLL)
4453 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4454 else if (style & WS_VSCROLL)
4455 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4456 else
4457 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4459 si.fMask = SIF_PAGE;
4460 si.nPage = 5;
4461 SetScrollInfo(hwnd, ctl, &si, FALSE);
4462 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4464 si.fMask = SIF_POS;
4465 si.nPos = max - 1;
4466 SetScrollInfo(hwnd, ctl, &si, FALSE);
4467 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4469 si.fMask = SIF_RANGE;
4470 si.nMin = 0xdeadbeef;
4471 si.nMax = 0xdeadbeef;
4472 ret = GetScrollInfo(hwnd, ctl, &si);
4473 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4474 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4475 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4476 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4479 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4480 static void test_scroll_messages(HWND hwnd)
4482 SCROLLINFO si;
4483 INT min, max;
4484 BOOL ret;
4486 flush_events();
4487 flush_sequence();
4489 min = 0xdeadbeef;
4490 max = 0xdeadbeef;
4491 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4492 ok( ret, "GetScrollRange error %d\n", GetLastError());
4493 if (sequence->message != WmGetScrollRangeSeq[0].message)
4494 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4495 /* values of min and max are undefined */
4496 flush_sequence();
4498 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4499 ok( ret, "SetScrollRange error %d\n", GetLastError());
4500 if (sequence->message != WmSetScrollRangeSeq[0].message)
4501 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4502 flush_sequence();
4504 min = 0xdeadbeef;
4505 max = 0xdeadbeef;
4506 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4507 ok( ret, "GetScrollRange error %d\n", GetLastError());
4508 if (sequence->message != WmGetScrollRangeSeq[0].message)
4509 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4510 /* values of min and max are undefined */
4511 flush_sequence();
4513 si.cbSize = sizeof(si);
4514 si.fMask = SIF_RANGE;
4515 si.nMin = 20;
4516 si.nMax = 160;
4517 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4518 if (sequence->message != WmSetScrollRangeSeq[0].message)
4519 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4520 flush_sequence();
4522 si.fMask = SIF_PAGE;
4523 si.nPage = 10;
4524 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4525 if (sequence->message != WmSetScrollRangeSeq[0].message)
4526 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4527 flush_sequence();
4529 si.fMask = SIF_POS;
4530 si.nPos = 20;
4531 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4532 if (sequence->message != WmSetScrollRangeSeq[0].message)
4533 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4534 flush_sequence();
4536 si.fMask = SIF_RANGE;
4537 si.nMin = 0xdeadbeef;
4538 si.nMax = 0xdeadbeef;
4539 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4540 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4541 if (sequence->message != WmGetScrollInfoSeq[0].message)
4542 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4543 /* values of min and max are undefined */
4544 flush_sequence();
4546 /* set WS_HSCROLL */
4547 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4548 /* clear WS_HSCROLL */
4549 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4551 /* set WS_HSCROLL */
4552 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4553 /* clear WS_HSCROLL */
4554 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4556 /* set WS_VSCROLL */
4557 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4558 /* clear WS_VSCROLL */
4559 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4561 /* set WS_VSCROLL */
4562 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4563 /* clear WS_VSCROLL */
4564 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4567 static void test_showwindow(void)
4569 HWND hwnd, hchild;
4570 RECT rc;
4572 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4573 100, 100, 200, 200, 0, 0, 0, NULL);
4574 ok (hwnd != 0, "Failed to create overlapped window\n");
4575 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4576 0, 0, 10, 10, hwnd, 0, 0, NULL);
4577 ok (hchild != 0, "Failed to create child\n");
4578 flush_sequence();
4580 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4581 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4582 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4583 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4585 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4586 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4587 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4588 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4589 /* back to invisible */
4590 ShowWindow(hchild, SW_HIDE);
4591 ShowWindow(hwnd, SW_HIDE);
4592 flush_sequence();
4593 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4594 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4595 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4596 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4597 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4598 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4599 flush_sequence();
4600 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4601 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4602 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4603 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4604 ShowWindow( hwnd, SW_SHOW);
4605 flush_sequence();
4606 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4607 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4608 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4610 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4611 ShowWindow( hchild, SW_HIDE);
4612 flush_sequence();
4613 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4614 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4615 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4617 SetCapture(hchild);
4618 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4619 DestroyWindow(hchild);
4620 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4622 DestroyWindow(hwnd);
4623 flush_sequence();
4625 /* Popup windows */
4626 /* Test 1:
4627 * 1. Create invisible maximized popup window.
4628 * 2. Move and resize it.
4629 * 3. Show it maximized.
4631 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4632 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4633 100, 100, 200, 200, 0, 0, 0, NULL);
4634 ok (hwnd != 0, "Failed to create popup window\n");
4635 ok(IsZoomed(hwnd), "window should be maximized\n");
4636 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4638 GetWindowRect(hwnd, &rc);
4639 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4640 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4641 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4642 /* Reset window's size & position */
4643 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4644 ok(IsZoomed(hwnd), "window should be maximized\n");
4645 flush_sequence();
4647 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4648 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4649 ok(IsZoomed(hwnd), "window should be maximized\n");
4650 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4652 GetWindowRect(hwnd, &rc);
4653 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4654 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4655 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4656 DestroyWindow(hwnd);
4657 flush_sequence();
4659 /* Test again, this time the NC_PAINT message */
4660 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4661 100, 100, 200, 200, 0, 0, 0, NULL);
4662 ok (hwnd != 0, "Failed to create popup window\n");
4663 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4664 flush_sequence();
4665 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4666 ok_sequence(WmShowMaxPopupResizedSeq_todo,
4667 "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", TRUE);
4668 DestroyWindow(hwnd);
4669 flush_sequence();
4671 /* Test 2:
4672 * 1. Create invisible maximized popup window.
4673 * 2. Show it maximized.
4675 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4676 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4677 100, 100, 200, 200, 0, 0, 0, NULL);
4678 ok (hwnd != 0, "Failed to create popup window\n");
4679 ok(IsZoomed(hwnd), "window should be maximized\n");
4680 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4682 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4683 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4684 ok(IsZoomed(hwnd), "window should be maximized\n");
4685 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4686 DestroyWindow(hwnd);
4687 flush_sequence();
4689 /* Test 3:
4690 * 1. Create visible maximized popup window.
4692 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4693 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | 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 be maximized\n");
4697 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4698 DestroyWindow(hwnd);
4699 flush_sequence();
4701 /* Test 4:
4702 * 1. Create visible popup window.
4703 * 2. Maximize it.
4705 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4706 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4707 100, 100, 200, 200, 0, 0, 0, NULL);
4708 ok (hwnd != 0, "Failed to create popup window\n");
4709 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4710 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4712 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4713 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4714 ok(IsZoomed(hwnd), "window should be maximized\n");
4715 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4716 DestroyWindow(hwnd);
4717 flush_sequence();
4720 static void test_sys_menu(void)
4722 HWND hwnd;
4723 HMENU hmenu;
4724 UINT state;
4726 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4727 100, 100, 200, 200, 0, 0, 0, NULL);
4728 ok (hwnd != 0, "Failed to create overlapped window\n");
4730 flush_sequence();
4732 /* test existing window without CS_NOCLOSE style */
4733 hmenu = GetSystemMenu(hwnd, FALSE);
4734 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4736 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4737 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4738 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4740 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4741 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4743 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4744 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4745 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4747 EnableMenuItem(hmenu, SC_CLOSE, 0);
4748 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4750 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4751 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4752 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4754 /* test whether removing WS_SYSMENU destroys a system menu */
4755 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4756 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4757 flush_sequence();
4758 hmenu = GetSystemMenu(hwnd, FALSE);
4759 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4761 DestroyWindow(hwnd);
4763 /* test new window with CS_NOCLOSE style */
4764 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
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 != 0, "GetSystemMenu error %d\n", GetLastError());
4771 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4772 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4774 DestroyWindow(hwnd);
4776 /* test new window without WS_SYSMENU style */
4777 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4778 100, 100, 200, 200, 0, 0, 0, NULL);
4779 ok(hwnd != 0, "Failed to create overlapped window\n");
4781 hmenu = GetSystemMenu(hwnd, FALSE);
4782 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4784 DestroyWindow(hwnd);
4787 /* For shown WS_OVERLAPPEDWINDOW */
4788 static const struct message WmSetIcon_1[] = {
4789 { WM_SETICON, sent },
4790 { 0x00AE, sent|defwinproc|optional }, /* XP */
4791 { WM_GETTEXT, sent|defwinproc|optional },
4792 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4793 { 0 }
4796 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4797 static const struct message WmSetIcon_2[] = {
4798 { WM_SETICON, sent },
4799 { 0 }
4802 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4803 static const struct message WmInitEndSession[] = {
4804 { 0x003B, sent },
4805 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4806 { 0 }
4809 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4810 static const struct message WmInitEndSession_2[] = {
4811 { 0x003B, sent },
4812 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4813 { 0 }
4816 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4817 static const struct message WmInitEndSession_3[] = {
4818 { 0x003B, sent },
4819 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4820 { 0 }
4823 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4824 static const struct message WmInitEndSession_4[] = {
4825 { 0x003B, sent },
4826 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4827 { 0 }
4830 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4831 static const struct message WmInitEndSession_5[] = {
4832 { 0x003B, sent },
4833 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4834 { 0 }
4837 static const struct message WmOptionalPaint[] = {
4838 { WM_PAINT, sent|optional },
4839 { WM_NCPAINT, sent|beginpaint|optional },
4840 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4841 { WM_ERASEBKGND, sent|beginpaint|optional },
4842 { 0 }
4845 static const struct message WmZOrder[] = {
4846 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4847 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4848 { HCBT_ACTIVATE, hook },
4849 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4850 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4851 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4852 { WM_GETTEXT, sent|optional },
4853 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4854 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4855 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4856 { WM_GETTEXT, sent|defwinproc|optional },
4857 { WM_GETTEXT, sent|defwinproc|optional },
4858 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4859 { HCBT_SETFOCUS, hook },
4860 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4861 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4862 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4863 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4864 { WM_GETTEXT, sent|optional },
4865 { WM_NCCALCSIZE, sent|optional },
4866 { 0 }
4869 static void CALLBACK apc_test_proc(ULONG_PTR param)
4871 /* nothing */
4874 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4876 DWORD ret;
4877 MSG msg;
4879 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4880 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4882 PostMessageA(hwnd, WM_USER, 0, 0);
4884 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4885 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4887 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4888 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4890 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4891 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4893 PostMessageA(hwnd, WM_USER, 0, 0);
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_NOREMOVE ), "PeekMessage should succeed\n");
4899 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4901 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4902 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4903 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4905 PostMessageA(hwnd, WM_USER, 0, 0);
4907 /* new incoming message causes it to become signaled again */
4908 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4909 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects 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);
4913 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4914 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4916 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
4917 PostMessageA( hwnd, WM_USER, 0, 0 );
4918 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4919 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4921 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
4922 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4924 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4925 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4927 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
4928 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
4929 ok(ret, "QueueUserAPC failed %u\n", GetLastError());
4931 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
4932 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4934 /* but even with MWMO_ALERTABLE window events are preferred */
4935 PostMessageA( hwnd, WM_USER, 0, 0 );
4937 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
4938 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4940 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4941 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4943 /* the APC call is still queued */
4944 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
4945 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4948 static void test_WM_DEVICECHANGE(HWND hwnd)
4950 DWORD ret;
4951 MSG msg;
4952 int i;
4953 static const WPARAM wparams[] = {0,
4954 DBT_DEVNODES_CHANGED,
4955 DBT_QUERYCHANGECONFIG,
4956 DBT_CONFIGCHANGED,
4957 DBT_CONFIGCHANGECANCELED,
4958 DBT_NO_DISK_SPACE,
4959 DBT_LOW_DISK_SPACE,
4960 DBT_CONFIGMGPRIVATE, /* 0x7fff */
4961 DBT_DEVICEARRIVAL, /* 0x8000 */
4962 DBT_DEVICEQUERYREMOVE,
4963 DBT_DEVICEQUERYREMOVEFAILED,
4964 DBT_DEVICEREMOVEPENDING,
4965 DBT_DEVICEREMOVECOMPLETE,
4966 DBT_DEVICETYPESPECIFIC,
4967 DBT_CUSTOMEVENT};
4969 for (i = 0; i < sizeof(wparams)/sizeof(wparams[0]); i++)
4971 SetLastError(0xdeadbeef);
4972 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
4973 if (wparams[i] & 0x8000)
4975 ok(ret == FALSE, "PostMessage should returned %d\n", ret);
4976 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
4978 else
4980 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4981 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4982 memset(&msg, 0, sizeof(msg));
4983 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
4984 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
4989 static DWORD CALLBACK show_window_thread(LPVOID arg)
4991 HWND hwnd = arg;
4993 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
4994 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
4996 return 0;
4999 /* Helper function to easier test SetWindowPos messages */
5000 #define test_msg_setpos( expected_list, flags, todo ) \
5001 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5002 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5004 HWND hwnd;
5006 flush_events();
5007 flush_sequence();
5008 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5009 10, 10, 100, 100, NULL, 0, 0, NULL );
5010 ok (hwnd != 0, "Failed to create popup window\n");
5011 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5012 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5013 DestroyWindow(hwnd);
5016 /* test if we receive the right sequence of messages */
5017 static void test_messages(void)
5019 DWORD tid;
5020 HANDLE hthread;
5021 HWND hwnd, hparent, hchild;
5022 HWND hchild2, hbutton;
5023 HMENU hmenu;
5024 MSG msg;
5025 LRESULT res;
5026 POINT pos;
5027 BOOL ret;
5029 flush_sequence();
5031 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5032 100, 100, 200, 200, 0, 0, 0, NULL);
5033 ok (hwnd != 0, "Failed to create overlapped window\n");
5034 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5036 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5037 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5038 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5040 /* test WM_SETREDRAW on a not visible top level window */
5041 test_WM_SETREDRAW(hwnd);
5043 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5044 flush_events();
5045 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5046 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5048 ok(GetActiveWindow() == hwnd, "window should be active\n");
5049 ok(GetFocus() == hwnd, "window should have input focus\n");
5050 ShowWindow(hwnd, SW_HIDE);
5051 flush_events();
5052 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5054 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5055 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5056 flush_events();
5057 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5059 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5060 hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5061 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5062 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5063 CloseHandle(hthread);
5064 flush_events();
5065 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5067 ShowWindow(hwnd, SW_SHOW);
5068 flush_events();
5069 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5071 ShowWindow(hwnd, SW_HIDE);
5072 flush_events();
5073 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5075 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5076 flush_events();
5077 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5078 flush_sequence();
5080 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5082 ShowWindow(hwnd, SW_RESTORE);
5083 flush_events();
5084 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5085 flush_sequence();
5088 ShowWindow(hwnd, SW_MINIMIZE);
5089 flush_events();
5090 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5091 flush_sequence();
5093 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5095 ShowWindow(hwnd, SW_RESTORE);
5096 flush_events();
5097 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5098 flush_sequence();
5101 ShowWindow(hwnd, SW_SHOW);
5102 flush_events();
5103 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5105 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5106 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5107 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5108 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5110 /* test WM_SETREDRAW on a visible top level window */
5111 ShowWindow(hwnd, SW_SHOW);
5112 flush_events();
5113 test_WM_SETREDRAW(hwnd);
5115 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5116 test_scroll_messages(hwnd);
5118 /* test resizing and moving */
5119 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5120 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5121 flush_events();
5122 flush_sequence();
5123 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5124 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5125 flush_events();
5126 flush_sequence();
5127 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5128 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5129 flush_events();
5130 flush_sequence();
5132 /* popups don't get WM_GETMINMAXINFO */
5133 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5134 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5135 flush_sequence();
5136 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5137 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5139 DestroyWindow(hwnd);
5140 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5142 /* Test if windows are correctly drawn when first shown */
5144 /* Visible, redraw */
5145 flush_events();
5146 flush_sequence();
5147 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5148 10, 10, 100, 100, NULL, 0, 0, NULL );
5149 ok (hwnd != 0, "Failed to create popup window\n");
5150 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5151 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5152 DestroyWindow(hwnd);
5154 /* Invisible, show, message */
5155 flush_events();
5156 flush_sequence();
5157 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5158 10, 10, 100, 100, NULL, 0, 0, NULL );
5159 ok (hwnd != 0, "Failed to create popup window\n");
5160 ShowWindow(hwnd, SW_SHOW);
5161 SendMessageW(hwnd, WM_PAINT, 0, 0);
5162 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5163 DestroyWindow(hwnd);
5165 /* Invisible, show maximized, redraw */
5166 flush_events();
5167 flush_sequence();
5168 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5169 10, 10, 100, 100, NULL, 0, 0, NULL );
5170 ok (hwnd != 0, "Failed to create popup window\n");
5171 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5172 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5173 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5174 DestroyWindow(hwnd);
5176 /* Test SetWindowPos */
5177 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5178 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5179 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5180 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5182 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5183 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5184 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5185 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5186 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5188 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5189 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5190 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5191 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5192 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5193 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5195 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5196 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5197 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5198 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5199 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5200 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5202 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5203 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5204 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5205 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5206 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5207 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5209 /* Test SetWindowPos with child windows */
5210 flush_events();
5211 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5212 100, 100, 200, 200, 0, 0, 0, NULL);
5213 ok (hparent != 0, "Failed to create parent window\n");
5215 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5216 0, 0, 10, 10, hparent, 0, 0, NULL);
5217 ok (hchild != 0, "Failed to create child window\n");
5218 flush_sequence();
5219 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5220 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5221 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5222 DestroyWindow(hchild);
5223 DestroyWindow(hparent);
5225 flush_events();
5226 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5227 100, 100, 200, 200, 0, 0, 0, NULL);
5228 ok (hparent != 0, "Failed to create parent window\n");
5230 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5231 0, 0, 10, 10, hparent, 0, 0, NULL);
5232 ok (hchild != 0, "Failed to create child window\n");
5233 flush_sequence();
5234 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5235 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5236 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5237 DestroyWindow(hchild);
5238 DestroyWindow(hparent);
5240 /* Test message sequence for extreme position and size */
5242 flush_sequence();
5243 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5244 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5245 ok (hwnd != 0, "Failed to create popup window\n");
5246 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE);
5247 DestroyWindow(hwnd);
5250 /* Test child windows */
5252 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5253 100, 100, 200, 200, 0, 0, 0, NULL);
5254 ok (hparent != 0, "Failed to create parent window\n");
5255 flush_sequence();
5257 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5258 0, 0, 10, 10, hparent, 0, 0, NULL);
5259 ok (hchild != 0, "Failed to create child window\n");
5260 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5261 DestroyWindow(hchild);
5262 flush_sequence();
5264 /* visible child window with a caption */
5265 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5266 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5267 0, 0, 10, 10, hparent, 0, 0, NULL);
5268 ok (hchild != 0, "Failed to create child window\n");
5269 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5271 trace("testing scroll APIs on a visible child window %p\n", hchild);
5272 test_scroll_messages(hchild);
5274 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5275 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5277 DestroyWindow(hchild);
5278 flush_sequence();
5280 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5281 0, 0, 10, 10, hparent, 0, 0, NULL);
5282 ok (hchild != 0, "Failed to create child window\n");
5283 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5285 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5286 100, 100, 50, 50, hparent, 0, 0, NULL);
5287 ok (hchild2 != 0, "Failed to create child2 window\n");
5288 flush_sequence();
5290 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5291 0, 100, 50, 50, hchild, 0, 0, NULL);
5292 ok (hbutton != 0, "Failed to create button window\n");
5294 /* test WM_SETREDRAW on a not visible child window */
5295 test_WM_SETREDRAW(hchild);
5297 ShowWindow(hchild, SW_SHOW);
5298 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5300 /* check parent messages too */
5301 log_all_parent_messages++;
5302 ShowWindow(hchild, SW_HIDE);
5303 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5304 log_all_parent_messages--;
5306 ShowWindow(hchild, SW_SHOW);
5307 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5309 ShowWindow(hchild, SW_HIDE);
5310 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5312 ShowWindow(hchild, SW_SHOW);
5313 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5315 /* test WM_SETREDRAW on a visible child window */
5316 test_WM_SETREDRAW(hchild);
5318 log_all_parent_messages++;
5319 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5320 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5321 log_all_parent_messages--;
5323 ShowWindow(hchild, SW_HIDE);
5324 flush_sequence();
5325 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5326 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5328 ShowWindow(hchild, SW_HIDE);
5329 flush_sequence();
5330 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5331 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5333 /* DestroyWindow sequence below expects that a child has focus */
5334 SetFocus(hchild);
5335 flush_sequence();
5337 DestroyWindow(hchild);
5338 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5339 DestroyWindow(hchild2);
5340 DestroyWindow(hbutton);
5342 flush_sequence();
5343 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5344 0, 0, 100, 100, hparent, 0, 0, NULL);
5345 ok (hchild != 0, "Failed to create child popup window\n");
5346 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5347 DestroyWindow(hchild);
5349 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5350 flush_sequence();
5351 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5352 0, 0, 100, 100, hparent, 0, 0, NULL);
5353 ok (hchild != 0, "Failed to create popup window\n");
5354 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5355 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5356 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5357 flush_sequence();
5358 ShowWindow(hchild, SW_SHOW);
5359 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5360 flush_sequence();
5361 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5362 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5363 flush_sequence();
5364 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5365 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5366 DestroyWindow(hchild);
5368 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5369 * changes nothing in message sequences.
5371 flush_sequence();
5372 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5373 0, 0, 100, 100, hparent, 0, 0, NULL);
5374 ok (hchild != 0, "Failed to create popup window\n");
5375 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5376 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5377 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5378 flush_sequence();
5379 ShowWindow(hchild, SW_SHOW);
5380 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5381 flush_sequence();
5382 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5383 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5384 DestroyWindow(hchild);
5386 flush_sequence();
5387 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5388 0, 0, 100, 100, hparent, 0, 0, NULL);
5389 ok(hwnd != 0, "Failed to create custom dialog window\n");
5390 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5392 if(0) {
5393 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5394 test_scroll_messages(hwnd);
5397 flush_sequence();
5399 test_def_id = TRUE;
5400 SendMessageA(hwnd, WM_NULL, 0, 0);
5402 flush_sequence();
5403 after_end_dialog = TRUE;
5404 EndDialog( hwnd, 0 );
5405 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5407 DestroyWindow(hwnd);
5408 after_end_dialog = FALSE;
5409 test_def_id = FALSE;
5411 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5412 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5414 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5415 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5416 ok(hwnd != 0, "Failed to create custom dialog window\n");
5417 flush_sequence();
5418 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5419 ShowWindow(hwnd, SW_SHOW);
5420 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5422 flush_events();
5423 flush_sequence();
5424 ret = DrawMenuBar(hwnd);
5425 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5426 flush_events();
5427 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5428 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5430 DestroyWindow(hwnd);
5432 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5433 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5434 ok(hwnd != 0, "Failed to create custom dialog window\n");
5435 flush_events();
5436 flush_sequence();
5437 ret = DrawMenuBar(hwnd);
5438 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5439 flush_events();
5440 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5442 DestroyWindow(hwnd);
5444 flush_sequence();
5445 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5446 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5448 DestroyWindow(hparent);
5449 flush_sequence();
5451 /* Message sequence for SetMenu */
5452 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5453 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5454 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5456 hmenu = CreateMenu();
5457 ok (hmenu != 0, "Failed to create menu\n");
5458 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5459 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5460 100, 100, 200, 200, 0, hmenu, 0, NULL);
5461 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5462 ok (SetMenu(hwnd, 0), "SetMenu\n");
5463 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5464 ok (SetMenu(hwnd, 0), "SetMenu\n");
5465 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5466 ShowWindow(hwnd, SW_SHOW);
5467 UpdateWindow( hwnd );
5468 flush_events();
5469 flush_sequence();
5470 ok (SetMenu(hwnd, 0), "SetMenu\n");
5471 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5472 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5473 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5475 UpdateWindow( hwnd );
5476 flush_events();
5477 flush_sequence();
5478 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5479 flush_events();
5480 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5482 DestroyWindow(hwnd);
5483 flush_sequence();
5485 /* Message sequence for EnableWindow */
5486 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5487 100, 100, 200, 200, 0, 0, 0, NULL);
5488 ok (hparent != 0, "Failed to create parent window\n");
5489 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5490 0, 0, 10, 10, hparent, 0, 0, NULL);
5491 ok (hchild != 0, "Failed to create child window\n");
5493 SetFocus(hchild);
5494 flush_events();
5495 flush_sequence();
5497 EnableWindow(hparent, FALSE);
5498 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5500 EnableWindow(hparent, FALSE);
5501 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5503 EnableWindow(hparent, TRUE);
5504 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5506 EnableWindow(hparent, TRUE);
5507 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5509 flush_events();
5510 flush_sequence();
5512 test_MsgWaitForMultipleObjects(hparent);
5513 test_WM_DEVICECHANGE(hparent);
5515 /* the following test causes an exception in user.exe under win9x */
5516 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5518 DestroyWindow(hparent);
5519 flush_sequence();
5520 return;
5522 PostMessageW( hparent, WM_USER+1, 0, 0 );
5523 /* PeekMessage(NULL) fails, but still removes the message */
5524 SetLastError(0xdeadbeef);
5525 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5526 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5527 GetLastError() == 0xdeadbeef, /* NT4 */
5528 "last error is %d\n", GetLastError() );
5529 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5530 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5532 DestroyWindow(hchild);
5533 DestroyWindow(hparent);
5534 flush_sequence();
5536 /* Message sequences for WM_SETICON */
5537 trace("testing WM_SETICON\n");
5538 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5539 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5540 NULL, NULL, 0);
5541 ShowWindow(hwnd, SW_SHOW);
5542 UpdateWindow(hwnd);
5543 flush_events();
5544 flush_sequence();
5545 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5546 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5548 ShowWindow(hwnd, SW_HIDE);
5549 flush_events();
5550 flush_sequence();
5551 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5552 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5553 DestroyWindow(hwnd);
5554 flush_sequence();
5556 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5557 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5558 NULL, NULL, 0);
5559 ShowWindow(hwnd, SW_SHOW);
5560 UpdateWindow(hwnd);
5561 flush_events();
5562 flush_sequence();
5563 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5564 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5566 ShowWindow(hwnd, SW_HIDE);
5567 flush_events();
5568 flush_sequence();
5569 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5570 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5572 flush_sequence();
5573 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5574 if (!res)
5576 todo_wine win_skip( "Message 0x3b not supported\n" );
5577 goto done;
5579 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5580 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5581 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5582 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5583 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5584 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5585 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5586 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5588 flush_sequence();
5589 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5590 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5591 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5592 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5593 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5594 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5596 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5597 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5598 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5600 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5601 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5602 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5604 done:
5605 DestroyWindow(hwnd);
5606 flush_sequence();
5609 static void test_setwindowpos(void)
5611 HWND hwnd;
5612 RECT rc;
5613 LRESULT res;
5614 const INT winX = 100;
5615 const INT winY = 100;
5616 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5618 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5619 0, 0, winX, winY, 0,
5620 NULL, NULL, 0);
5622 GetWindowRect(hwnd, &rc);
5623 expect(sysX, rc.right);
5624 expect(winY, rc.bottom);
5626 flush_events();
5627 flush_sequence();
5628 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5629 ok_sequence(WmZOrder, "Z-Order", TRUE);
5630 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5632 GetWindowRect(hwnd, &rc);
5633 expect(sysX, rc.right);
5634 expect(winY, rc.bottom);
5635 DestroyWindow(hwnd);
5638 static void invisible_parent_tests(void)
5640 HWND hparent, hchild;
5642 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5643 100, 100, 200, 200, 0, 0, 0, NULL);
5644 ok (hparent != 0, "Failed to create parent window\n");
5645 flush_sequence();
5647 /* test showing child with hidden parent */
5649 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5650 0, 0, 10, 10, hparent, 0, 0, NULL);
5651 ok (hchild != 0, "Failed to create child window\n");
5652 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5654 ShowWindow( hchild, SW_MINIMIZE );
5655 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5656 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5657 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5659 /* repeat */
5660 flush_events();
5661 flush_sequence();
5662 ShowWindow( hchild, SW_MINIMIZE );
5663 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5665 DestroyWindow(hchild);
5666 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5667 0, 0, 10, 10, hparent, 0, 0, NULL);
5668 flush_sequence();
5670 ShowWindow( hchild, SW_MAXIMIZE );
5671 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5672 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5673 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5675 /* repeat */
5676 flush_events();
5677 flush_sequence();
5678 ShowWindow( hchild, SW_MAXIMIZE );
5679 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5681 DestroyWindow(hchild);
5682 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5683 0, 0, 10, 10, hparent, 0, 0, NULL);
5684 flush_sequence();
5686 ShowWindow( hchild, SW_RESTORE );
5687 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5688 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5689 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5691 DestroyWindow(hchild);
5692 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5693 0, 0, 10, 10, hparent, 0, 0, NULL);
5694 flush_sequence();
5696 ShowWindow( hchild, SW_SHOWMINIMIZED );
5697 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5698 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5699 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5701 /* repeat */
5702 flush_events();
5703 flush_sequence();
5704 ShowWindow( hchild, SW_SHOWMINIMIZED );
5705 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5707 DestroyWindow(hchild);
5708 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5709 0, 0, 10, 10, hparent, 0, 0, NULL);
5710 flush_sequence();
5712 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5713 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5714 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5715 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5716 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5718 DestroyWindow(hchild);
5719 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5720 0, 0, 10, 10, hparent, 0, 0, NULL);
5721 flush_sequence();
5723 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5724 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5725 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5726 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5728 /* repeat */
5729 flush_events();
5730 flush_sequence();
5731 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5732 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5734 DestroyWindow(hchild);
5735 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5736 0, 0, 10, 10, hparent, 0, 0, NULL);
5737 flush_sequence();
5739 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5740 ShowWindow( hchild, SW_FORCEMINIMIZE );
5741 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5742 todo_wine {
5743 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5745 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5747 DestroyWindow(hchild);
5748 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5749 0, 0, 10, 10, hparent, 0, 0, NULL);
5750 flush_sequence();
5752 ShowWindow( hchild, SW_SHOWNA );
5753 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5754 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5755 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5757 /* repeat */
5758 flush_events();
5759 flush_sequence();
5760 ShowWindow( hchild, SW_SHOWNA );
5761 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5763 DestroyWindow(hchild);
5764 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5765 0, 0, 10, 10, hparent, 0, 0, NULL);
5766 flush_sequence();
5768 ShowWindow( hchild, SW_SHOW );
5769 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5770 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5771 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5773 /* repeat */
5774 flush_events();
5775 flush_sequence();
5776 ShowWindow( hchild, SW_SHOW );
5777 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5779 ShowWindow( hchild, SW_HIDE );
5780 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5781 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5782 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5784 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5785 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5786 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5787 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5789 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5790 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5791 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5792 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5794 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5795 flush_sequence();
5796 DestroyWindow(hchild);
5797 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5799 DestroyWindow(hparent);
5800 flush_sequence();
5803 /****************** button message test *************************/
5804 #define ID_BUTTON 0x000e
5806 static const struct message WmSetFocusButtonSeq[] =
5808 { HCBT_SETFOCUS, hook },
5809 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5810 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5811 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5812 { WM_SETFOCUS, sent|wparam, 0 },
5813 { WM_CTLCOLORBTN, sent|parent },
5814 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5815 { WM_APP, sent|wparam|lparam, 0, 0 },
5816 { 0 }
5818 static const struct message WmKillFocusButtonSeq[] =
5820 { HCBT_SETFOCUS, hook },
5821 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5822 { WM_KILLFOCUS, sent|wparam, 0 },
5823 { WM_CTLCOLORBTN, sent|parent },
5824 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5825 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5826 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5827 { WM_APP, sent|wparam|lparam, 0, 0 },
5828 { WM_PAINT, sent },
5829 { WM_CTLCOLORBTN, sent|parent },
5830 { 0 }
5832 static const struct message WmSetFocusStaticSeq[] =
5834 { HCBT_SETFOCUS, hook },
5835 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5836 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5837 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5838 { WM_SETFOCUS, sent|wparam, 0 },
5839 { WM_CTLCOLORSTATIC, sent|parent },
5840 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5841 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5842 { WM_APP, sent|wparam|lparam, 0, 0 },
5843 { 0 }
5845 static const struct message WmKillFocusStaticSeq[] =
5847 { HCBT_SETFOCUS, hook },
5848 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5849 { WM_KILLFOCUS, sent|wparam, 0 },
5850 { WM_CTLCOLORSTATIC, sent|parent },
5851 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5852 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5853 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5854 { WM_APP, sent|wparam|lparam, 0, 0 },
5855 { WM_PAINT, sent },
5856 { WM_CTLCOLORSTATIC, sent|parent },
5857 { 0 }
5859 static const struct message WmSetFocusOwnerdrawSeq[] =
5861 { HCBT_SETFOCUS, hook },
5862 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5863 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5864 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5865 { WM_SETFOCUS, sent|wparam, 0 },
5866 { WM_CTLCOLORBTN, sent|parent },
5867 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5868 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5869 { WM_APP, sent|wparam|lparam, 0, 0 },
5870 { 0 }
5872 static const struct message WmKillFocusOwnerdrawSeq[] =
5874 { HCBT_SETFOCUS, hook },
5875 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5876 { WM_KILLFOCUS, sent|wparam, 0 },
5877 { WM_CTLCOLORBTN, sent|parent },
5878 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5879 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5880 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5881 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5882 { WM_APP, sent|wparam|lparam, 0, 0 },
5883 { WM_PAINT, sent },
5884 { WM_CTLCOLORBTN, sent|parent },
5885 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5886 { 0 }
5888 static const struct message WmLButtonDownSeq[] =
5890 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5891 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5892 { HCBT_SETFOCUS, hook },
5893 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5894 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5895 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5896 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5897 { WM_CTLCOLORBTN, sent|defwinproc },
5898 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5899 { WM_CTLCOLORBTN, sent|defwinproc },
5900 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5901 { 0 }
5903 static const struct message WmLButtonDownStaticSeq[] =
5905 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5906 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5907 { HCBT_SETFOCUS, hook },
5908 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5909 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5910 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5911 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5912 { WM_CTLCOLORSTATIC, sent|defwinproc },
5913 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5914 { WM_CTLCOLORSTATIC, sent|defwinproc },
5915 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5916 { 0 }
5918 static const struct message WmLButtonUpSeq[] =
5920 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5921 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5922 { WM_CTLCOLORBTN, sent|defwinproc },
5923 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5924 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5925 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5926 { 0 }
5928 static const struct message WmLButtonUpStaticSeq[] =
5930 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5931 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5932 { WM_CTLCOLORSTATIC, sent|defwinproc },
5933 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5934 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5935 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5936 { 0 }
5938 static const struct message WmLButtonUpAutoSeq[] =
5940 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5941 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5942 { WM_CTLCOLORSTATIC, sent|defwinproc },
5943 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5944 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5945 { BM_SETCHECK, sent|defwinproc },
5946 { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
5947 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5948 { 0 }
5950 static const struct message WmLButtonUpBrokenSeq[] =
5952 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5953 { 0 }
5955 static const struct message WmSetFontButtonSeq[] =
5957 { WM_SETFONT, sent },
5958 { WM_PAINT, sent },
5959 { WM_ERASEBKGND, sent|defwinproc|optional },
5960 { WM_CTLCOLORBTN, sent|defwinproc },
5961 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
5962 { 0 }
5964 static const struct message WmSetFontStaticSeq[] =
5966 { WM_SETFONT, sent },
5967 { WM_PAINT, sent },
5968 { WM_ERASEBKGND, sent|defwinproc|optional },
5969 { WM_CTLCOLORSTATIC, sent|defwinproc },
5970 { 0 }
5972 static const struct message WmSetTextButtonSeq[] =
5974 { WM_SETTEXT, sent },
5975 { WM_CTLCOLORBTN, sent|parent },
5976 { WM_CTLCOLORBTN, sent|parent },
5977 { WM_COMMAND, sent|parent|optional },
5978 { WM_DRAWITEM, sent|parent|optional },
5979 { 0 }
5981 static const struct message WmSetTextStaticSeq[] =
5983 { WM_SETTEXT, sent },
5984 { WM_CTLCOLORSTATIC, sent|parent },
5985 { WM_CTLCOLORSTATIC, sent|parent },
5986 { 0 }
5988 static const struct message WmSetTextGroupSeq[] =
5990 { WM_SETTEXT, sent },
5991 { WM_CTLCOLORSTATIC, sent|parent },
5992 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
5993 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
5994 { 0 }
5996 static const struct message WmSetTextInvisibleSeq[] =
5998 { WM_SETTEXT, sent },
5999 { 0 }
6001 static const struct message WmSetStyleButtonSeq[] =
6003 { BM_SETSTYLE, sent },
6004 { WM_APP, sent|wparam|lparam, 0, 0 },
6005 { WM_PAINT, sent },
6006 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6007 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6008 { WM_CTLCOLORBTN, sent|parent },
6009 { 0 }
6011 static const struct message WmSetStyleStaticSeq[] =
6013 { BM_SETSTYLE, sent },
6014 { WM_APP, sent|wparam|lparam, 0, 0 },
6015 { WM_PAINT, sent },
6016 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6017 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6018 { WM_CTLCOLORSTATIC, sent|parent },
6019 { 0 }
6021 static const struct message WmSetStyleUserSeq[] =
6023 { BM_SETSTYLE, sent },
6024 { WM_APP, sent|wparam|lparam, 0, 0 },
6025 { WM_PAINT, sent },
6026 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6027 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6028 { WM_CTLCOLORBTN, sent|parent },
6029 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6030 { 0 }
6032 static const struct message WmSetStyleOwnerdrawSeq[] =
6034 { BM_SETSTYLE, sent },
6035 { WM_APP, sent|wparam|lparam, 0, 0 },
6036 { WM_PAINT, sent },
6037 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6038 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6039 { WM_CTLCOLORBTN, sent|parent },
6040 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6041 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6042 { 0 }
6044 static const struct message WmSetStateButtonSeq[] =
6046 { BM_SETSTATE, sent },
6047 { WM_CTLCOLORBTN, sent|parent },
6048 { WM_APP, sent|wparam|lparam, 0, 0 },
6049 { 0 }
6051 static const struct message WmSetStateStaticSeq[] =
6053 { BM_SETSTATE, sent },
6054 { WM_CTLCOLORSTATIC, sent|parent },
6055 { WM_APP, sent|wparam|lparam, 0, 0 },
6056 { 0 }
6058 static const struct message WmSetStateUserSeq[] =
6060 { BM_SETSTATE, sent },
6061 { WM_CTLCOLORBTN, sent|parent },
6062 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6063 { WM_APP, sent|wparam|lparam, 0, 0 },
6064 { 0 }
6066 static const struct message WmSetStateOwnerdrawSeq[] =
6068 { BM_SETSTATE, sent },
6069 { WM_CTLCOLORBTN, sent|parent },
6070 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6071 { WM_APP, sent|wparam|lparam, 0, 0 },
6072 { 0 }
6074 static const struct message WmClearStateButtonSeq[] =
6076 { BM_SETSTATE, sent },
6077 { WM_CTLCOLORBTN, sent|parent },
6078 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6079 { WM_APP, sent|wparam|lparam, 0, 0 },
6080 { 0 }
6082 static const struct message WmDisableButtonSeq[] =
6084 { WM_LBUTTONDOWN, sent },
6085 { BM_SETSTATE, sent|defwinproc },
6086 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6087 { WM_CTLCOLORBTN, sent|optional },
6088 { WM_LBUTTONUP, sent },
6089 { BM_SETSTATE, sent|defwinproc },
6090 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6091 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6092 { BM_SETCHECK, sent|defwinproc|optional },
6093 { WM_CTLCOLORBTN, sent|optional },
6094 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6095 { WM_CAPTURECHANGED, sent|defwinproc },
6096 { WM_COMMAND, sent },
6097 { 0 }
6099 static const struct message WmClearStateOwnerdrawSeq[] =
6101 { BM_SETSTATE, sent },
6102 { WM_CTLCOLORBTN, sent|parent },
6103 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6104 { WM_APP, sent|wparam|lparam, 0, 0 },
6105 { 0 }
6107 static const struct message WmSetCheckIgnoredSeq[] =
6109 { BM_SETCHECK, sent },
6110 { WM_APP, sent|wparam|lparam, 0, 0 },
6111 { 0 }
6113 static const struct message WmSetCheckStaticSeq[] =
6115 { BM_SETCHECK, sent },
6116 { WM_CTLCOLORSTATIC, sent|parent },
6117 { WM_APP, sent|wparam|lparam, 0, 0 },
6118 { 0 }
6121 static WNDPROC old_button_proc;
6123 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6125 static LONG defwndproc_counter = 0;
6126 LRESULT ret;
6127 struct recvd_message msg;
6129 if (ignore_message( message )) return 0;
6131 switch (message)
6133 case WM_SYNCPAINT:
6134 break;
6135 case BM_SETSTATE:
6136 if (GetCapture())
6137 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6138 /* fall through */
6139 default:
6140 msg.hwnd = hwnd;
6141 msg.message = message;
6142 msg.flags = sent|wparam|lparam;
6143 if (defwndproc_counter) msg.flags |= defwinproc;
6144 msg.wParam = wParam;
6145 msg.lParam = lParam;
6146 msg.descr = "button";
6147 add_message(&msg);
6150 defwndproc_counter++;
6151 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6152 defwndproc_counter--;
6154 return ret;
6157 static void subclass_button(void)
6159 WNDCLASSA cls;
6161 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6163 old_button_proc = cls.lpfnWndProc;
6165 cls.hInstance = GetModuleHandleA(NULL);
6166 cls.lpfnWndProc = button_hook_proc;
6167 cls.lpszClassName = "my_button_class";
6168 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6169 if (!RegisterClassA(&cls)) assert(0);
6172 static void test_button_messages(void)
6174 static const struct
6176 DWORD style;
6177 DWORD dlg_code;
6178 const struct message *setfocus;
6179 const struct message *killfocus;
6180 const struct message *setstyle;
6181 const struct message *setstate;
6182 const struct message *clearstate;
6183 const struct message *setcheck;
6184 const struct message *lbuttondown;
6185 const struct message *lbuttonup;
6186 const struct message *setfont;
6187 const struct message *settext;
6188 } button[] = {
6189 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6190 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6191 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6192 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6193 WmSetTextButtonSeq },
6194 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6195 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6196 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6197 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6198 WmSetTextButtonSeq },
6199 { BS_CHECKBOX, DLGC_BUTTON,
6200 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6201 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6202 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6203 WmSetTextStaticSeq },
6204 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6205 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6206 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6207 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6208 WmSetTextStaticSeq },
6209 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6210 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6211 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6212 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6213 WmSetTextStaticSeq },
6214 { BS_3STATE, DLGC_BUTTON,
6215 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6216 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6217 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6218 WmSetTextStaticSeq },
6219 { BS_AUTO3STATE, DLGC_BUTTON,
6220 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6221 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6222 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6223 WmSetTextStaticSeq },
6224 { BS_GROUPBOX, DLGC_STATIC,
6225 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6226 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6227 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6228 WmSetTextGroupSeq },
6229 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6230 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6231 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6232 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6233 WmSetTextButtonSeq },
6234 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6235 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6236 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6237 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6238 WmSetTextStaticSeq },
6239 { BS_OWNERDRAW, DLGC_BUTTON,
6240 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6241 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6242 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6243 WmSetTextButtonSeq },
6245 LOGFONTA logfont = { 0 };
6246 HFONT zfont, hfont2;
6247 unsigned int i;
6248 HWND hwnd, parent;
6249 DWORD dlg_code;
6251 /* selection with VK_SPACE should capture button window */
6252 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6253 0, 0, 50, 14, 0, 0, 0, NULL);
6254 ok(hwnd != 0, "Failed to create button window\n");
6255 ReleaseCapture();
6256 SetFocus(hwnd);
6257 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6258 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6259 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6260 DestroyWindow(hwnd);
6262 subclass_button();
6264 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6265 100, 100, 200, 200, 0, 0, 0, NULL);
6266 ok(parent != 0, "Failed to create parent window\n");
6268 memset(&logfont, 0, sizeof(logfont));
6269 logfont.lfHeight = -12;
6270 logfont.lfWeight = FW_NORMAL;
6271 strcpy(logfont.lfFaceName, "Tahoma");
6273 hfont2 = CreateFontIndirectA(&logfont);
6274 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6276 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
6278 MSG msg;
6279 DWORD style, state;
6280 HFONT prevfont;
6281 char desc[64];
6282 HDC hdc;
6284 trace("button style %08x\n", button[i].style);
6286 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6287 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6288 ok(hwnd != 0, "Failed to create button window\n");
6290 style = GetWindowLongA(hwnd, GWL_STYLE);
6291 style &= ~(WS_CHILD | BS_NOTIFY);
6292 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6293 if (button[i].style == BS_USERBUTTON)
6294 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6295 else
6296 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6298 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6299 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6301 ShowWindow(hwnd, SW_SHOW);
6302 UpdateWindow(hwnd);
6303 SetFocus(0);
6304 flush_events();
6305 SetFocus(0);
6306 flush_sequence();
6308 log_all_parent_messages++;
6310 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6311 SetFocus(hwnd);
6312 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6313 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6314 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6316 SetFocus(0);
6317 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6318 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6319 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6321 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6323 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6324 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6325 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6326 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6328 style = GetWindowLongA(hwnd, GWL_STYLE);
6329 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6330 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6331 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6333 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6334 ok(state == 0, "expected state 0, got %04x\n", state);
6336 flush_sequence();
6338 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6339 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6340 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6341 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6343 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6344 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6346 style = GetWindowLongA(hwnd, GWL_STYLE);
6347 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6348 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6350 flush_sequence();
6352 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6353 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6354 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6355 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6357 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6358 ok(state == 0, "expected state 0, got %04x\n", state);
6360 style = GetWindowLongA(hwnd, GWL_STYLE);
6361 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6362 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6364 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6365 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6367 flush_sequence();
6369 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6370 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6371 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6372 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6374 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6375 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6377 style = GetWindowLongA(hwnd, GWL_STYLE);
6378 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6379 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6381 flush_sequence();
6383 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6384 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6385 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6386 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6388 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6389 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6390 ok_sequence(button[i].settext, desc, FALSE);
6392 ShowWindow(hwnd, SW_HIDE);
6393 flush_events();
6394 flush_sequence();
6396 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6397 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6398 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6400 ShowWindow(hwnd, SW_SHOW);
6401 ShowWindow(parent, SW_HIDE);
6402 flush_events();
6403 flush_sequence();
6405 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6406 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6407 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6409 ShowWindow(parent, SW_SHOW);
6410 flush_events();
6412 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6413 if (button[i].style == BS_PUSHBUTTON ||
6414 button[i].style == BS_DEFPUSHBUTTON ||
6415 button[i].style == BS_GROUPBOX ||
6416 button[i].style == BS_USERBUTTON ||
6417 button[i].style == BS_OWNERDRAW)
6418 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6419 else
6420 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6422 style = GetWindowLongA(hwnd, GWL_STYLE);
6423 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6424 if (button[i].style == BS_RADIOBUTTON ||
6425 button[i].style == BS_AUTORADIOBUTTON)
6426 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6427 else
6428 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6430 log_all_parent_messages--;
6432 DestroyWindow(hwnd);
6434 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6435 0, 0, 50, 14, 0, 0, 0, NULL);
6436 ok(hwnd != 0, "Failed to create button window\n");
6438 SetForegroundWindow(hwnd);
6439 flush_events();
6441 SetActiveWindow(hwnd);
6442 SetFocus(0);
6443 flush_sequence();
6445 if (button[i].lbuttondown)
6447 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6448 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6449 ok_sequence(button[i].lbuttondown, desc, FALSE);
6452 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6453 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6454 ok_sequence(button[i].lbuttonup, desc, FALSE);
6456 flush_sequence();
6457 zfont = GetStockObject(DEFAULT_GUI_FONT);
6458 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6459 UpdateWindow(hwnd);
6460 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6461 ok_sequence(button[i].setfont, desc, FALSE);
6463 /* Test that original font is not selected back after painting */
6464 hdc = CreateCompatibleDC(0);
6466 prevfont = SelectObject(hdc, hfont2);
6467 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6468 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6469 todo_wine
6470 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6471 SelectObject(hdc, prevfont);
6473 prevfont = SelectObject(hdc, hfont2);
6474 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6475 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6476 todo_wine
6477 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6478 SelectObject(hdc, prevfont);
6480 DeleteDC(hdc);
6482 DestroyWindow(hwnd);
6485 DeleteObject(hfont2);
6486 DestroyWindow(parent);
6488 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6490 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6491 100, 100, 200, 200, 0, 0, 0, NULL);
6492 ok (hwnd != 0, "Failed to create overlapped window\n");
6494 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6495 0, 0, 50, 14, parent, 0, 0, NULL);
6497 EnableWindow(hwnd, FALSE);
6498 flush_sequence();
6499 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6500 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6501 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6503 DestroyWindow(hwnd);
6504 DestroyWindow(parent);
6507 /****************** static message test *************************/
6508 static const struct message WmSetFontStaticSeq2[] =
6510 { WM_SETFONT, sent },
6511 { WM_PAINT, sent|defwinproc|optional },
6512 { WM_ERASEBKGND, sent|defwinproc|optional },
6513 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6514 { 0 }
6517 static WNDPROC old_static_proc;
6519 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6521 static LONG defwndproc_counter = 0;
6522 LRESULT ret;
6523 struct recvd_message msg;
6525 if (ignore_message( message )) return 0;
6527 msg.hwnd = hwnd;
6528 msg.message = message;
6529 msg.flags = sent|wparam|lparam;
6530 if (defwndproc_counter) msg.flags |= defwinproc;
6531 msg.wParam = wParam;
6532 msg.lParam = lParam;
6533 msg.descr = "static";
6534 add_message(&msg);
6536 defwndproc_counter++;
6537 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
6538 defwndproc_counter--;
6540 return ret;
6543 static void subclass_static(void)
6545 WNDCLASSA cls;
6547 if (!GetClassInfoA(0, "static", &cls)) assert(0);
6549 old_static_proc = cls.lpfnWndProc;
6551 cls.hInstance = GetModuleHandleA(NULL);
6552 cls.lpfnWndProc = static_hook_proc;
6553 cls.lpszClassName = "my_static_class";
6554 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6555 if (!RegisterClassA(&cls)) assert(0);
6558 static void test_static_messages(void)
6560 /* FIXME: make as comprehensive as the button message test */
6561 static const struct
6563 DWORD style;
6564 DWORD dlg_code;
6565 const struct message *setfont;
6566 } static_ctrl[] = {
6567 { SS_LEFT, DLGC_STATIC,
6568 WmSetFontStaticSeq2 }
6570 unsigned int i;
6571 HWND hwnd;
6572 DWORD dlg_code;
6574 subclass_static();
6576 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
6578 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
6579 0, 0, 50, 14, 0, 0, 0, NULL);
6580 ok(hwnd != 0, "Failed to create static window\n");
6582 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6583 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6585 ShowWindow(hwnd, SW_SHOW);
6586 UpdateWindow(hwnd);
6587 SetFocus(0);
6588 flush_sequence();
6590 trace("static style %08x\n", static_ctrl[i].style);
6591 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
6592 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
6594 DestroyWindow(hwnd);
6598 /****************** ComboBox message test *************************/
6599 #define ID_COMBOBOX 0x000f
6601 static const struct message SetCurSelComboSeq[] =
6603 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
6604 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
6605 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
6606 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
6607 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
6608 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
6609 { LB_GETTEXT, sent|wparam, 0 },
6610 { WM_CTLCOLOREDIT, sent|parent },
6611 { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
6612 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
6613 { 0 }
6616 static const struct message WmKeyDownComboSeq[] =
6618 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
6619 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
6620 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
6621 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
6622 { WM_CTLCOLOREDIT, sent|parent },
6623 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
6624 { 0 }
6627 static const struct message WmSetPosComboSeq[] =
6629 { WM_WINDOWPOSCHANGING, sent },
6630 { WM_NCCALCSIZE, sent|wparam, TRUE },
6631 { WM_CHILDACTIVATE, sent },
6632 { WM_WINDOWPOSCHANGED, sent },
6633 { WM_MOVE, sent|defwinproc },
6634 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
6635 { WM_WINDOWPOSCHANGING, sent|defwinproc },
6636 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
6637 { WM_WINDOWPOSCHANGED, sent|defwinproc },
6638 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
6639 { 0 }
6642 static const struct message WMSetFocusComboBoxSeq[] =
6644 { WM_SETFOCUS, sent },
6645 { WM_KILLFOCUS, sent|parent },
6646 { WM_SETFOCUS, sent },
6647 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
6648 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
6649 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
6650 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
6651 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
6652 { 0 }
6655 static const struct message SetFocusButtonSeq[] =
6657 { WM_KILLFOCUS, sent },
6658 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
6659 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
6660 { WM_LBUTTONUP, sent|defwinproc },
6661 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
6662 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
6663 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
6664 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
6665 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
6666 { WM_CTLCOLORBTN, sent|parent },
6667 { 0 }
6670 static const struct message SetFocusComboBoxSeq[] =
6672 { WM_CTLCOLORBTN, sent|parent },
6673 { WM_SETFOCUS, sent },
6674 { WM_KILLFOCUS, sent|defwinproc },
6675 { WM_SETFOCUS, sent },
6676 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
6677 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
6678 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
6679 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
6680 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
6681 { 0 }
6684 static const struct message SetFocusButtonSeq2[] =
6686 { WM_KILLFOCUS, sent },
6687 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
6688 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
6689 { WM_LBUTTONUP, sent|defwinproc },
6690 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
6691 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
6692 { WM_CTLCOLOREDIT, sent|defwinproc },
6693 { WM_CTLCOLOREDIT, sent|parent },
6694 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
6695 { WM_CTLCOLORBTN, sent|parent },
6696 { 0 }
6699 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
6701 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
6702 WPARAM wParam, LPARAM lParam)
6704 static LONG defwndproc_counter = 0;
6705 LRESULT ret;
6706 struct recvd_message msg;
6708 /* do not log painting messages */
6709 if (message != WM_PAINT &&
6710 message != WM_NCPAINT &&
6711 message != WM_SYNCPAINT &&
6712 message != WM_ERASEBKGND &&
6713 message != WM_NCHITTEST &&
6714 message != WM_GETTEXT &&
6715 !ignore_message( message ))
6717 msg.hwnd = hwnd;
6718 msg.message = message;
6719 msg.flags = sent|wparam|lparam;
6720 if (defwndproc_counter) msg.flags |= defwinproc;
6721 msg.wParam = wParam;
6722 msg.lParam = lParam;
6723 msg.descr = "combo edit";
6724 add_message(&msg);
6727 defwndproc_counter++;
6728 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
6729 defwndproc_counter--;
6731 return ret;
6734 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
6735 WPARAM wParam, LPARAM lParam)
6737 static LONG defwndproc_counter = 0;
6738 LRESULT ret;
6739 struct recvd_message msg;
6741 /* do not log painting messages */
6742 if (message != WM_PAINT &&
6743 message != WM_NCPAINT &&
6744 message != WM_SYNCPAINT &&
6745 message != WM_ERASEBKGND &&
6746 message != WM_NCHITTEST &&
6747 !ignore_message( message ))
6749 msg.hwnd = hwnd;
6750 msg.message = message;
6751 msg.flags = sent|wparam|lparam;
6752 if (defwndproc_counter) msg.flags |= defwinproc;
6753 msg.wParam = wParam;
6754 msg.lParam = lParam;
6755 msg.descr = "combo lbox";
6756 add_message(&msg);
6759 defwndproc_counter++;
6760 ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
6761 defwndproc_counter--;
6763 return ret;
6766 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6768 static LONG defwndproc_counter = 0;
6769 LRESULT ret;
6770 struct recvd_message msg;
6772 /* do not log painting messages */
6773 if (message != WM_PAINT &&
6774 message != WM_NCPAINT &&
6775 message != WM_SYNCPAINT &&
6776 message != WM_ERASEBKGND &&
6777 message != WM_NCHITTEST &&
6778 message != WM_GETTEXT &&
6779 !ignore_message( message ))
6781 msg.hwnd = hwnd;
6782 msg.message = message;
6783 msg.flags = sent|wparam|lparam;
6784 if (defwndproc_counter) msg.flags |= defwinproc;
6785 msg.wParam = wParam;
6786 msg.lParam = lParam;
6787 msg.descr = "combo";
6788 add_message(&msg);
6791 defwndproc_counter++;
6792 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
6793 defwndproc_counter--;
6795 return ret;
6798 static void subclass_combobox(void)
6800 WNDCLASSA cls;
6802 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
6804 old_combobox_proc = cls.lpfnWndProc;
6806 cls.hInstance = GetModuleHandleA(NULL);
6807 cls.lpfnWndProc = combobox_hook_proc;
6808 cls.lpszClassName = "my_combobox_class";
6809 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6810 if (!RegisterClassA(&cls)) assert(0);
6813 static void test_combobox_messages(void)
6815 HWND parent, combo, button, edit, lbox;
6816 LRESULT ret;
6817 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
6818 COMBOBOXINFO cbInfo;
6819 BOOL res;
6821 subclass_combobox();
6823 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6824 100, 100, 200, 200, 0, 0, 0, NULL);
6825 ok(parent != 0, "Failed to create parent window\n");
6826 flush_sequence();
6828 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
6829 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
6830 ok(combo != 0, "Failed to create combobox window\n");
6832 UpdateWindow(combo);
6834 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
6835 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
6837 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
6838 ok(ret == 0, "expected 0, got %ld\n", ret);
6839 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
6840 ok(ret == 1, "expected 1, got %ld\n", ret);
6841 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
6842 ok(ret == 2, "expected 2, got %ld\n", ret);
6844 SendMessageA(combo, CB_SETCURSEL, 0, 0);
6845 SetFocus(combo);
6846 flush_sequence();
6848 log_all_parent_messages++;
6849 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
6850 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
6851 log_all_parent_messages--;
6852 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
6854 flush_sequence();
6855 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
6856 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
6858 DestroyWindow(combo);
6859 DestroyWindow(parent);
6861 /* Start again. Test combobox text selection when getting and losing focus */
6862 pGetComboBoxInfo = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
6863 if (!pGetComboBoxInfo)
6865 win_skip("GetComboBoxInfo is not available\n");
6866 return;
6869 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6870 10, 10, 300, 300, NULL, NULL, NULL, NULL);
6871 ok(parent != 0, "Failed to create parent window\n");
6873 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
6874 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
6875 ok(combo != 0, "Failed to create combobox window\n");
6877 cbInfo.cbSize = sizeof(COMBOBOXINFO);
6878 SetLastError(0xdeadbeef);
6879 res = pGetComboBoxInfo(combo, &cbInfo);
6880 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
6881 edit = cbInfo.hwndItem;
6883 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
6884 (ULONG_PTR)combobox_edit_subclass_proc);
6886 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
6887 5, 50, 100, 20, parent, NULL,
6888 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
6889 ok(button != 0, "Failed to create button window\n");
6891 flush_sequence();
6892 log_all_parent_messages++;
6893 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
6894 log_all_parent_messages--;
6895 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
6897 flush_sequence();
6898 log_all_parent_messages++;
6899 SetFocus(button);
6900 log_all_parent_messages--;
6901 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
6903 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
6905 flush_sequence();
6906 log_all_parent_messages++;
6907 SetFocus(combo);
6908 log_all_parent_messages--;
6909 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
6911 flush_sequence();
6912 log_all_parent_messages++;
6913 SetFocus(button);
6914 log_all_parent_messages--;
6915 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
6917 DestroyWindow(button);
6918 DestroyWindow(combo);
6920 combo = CreateWindowExA(0, "my_combobox_class", "test",
6921 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
6922 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
6923 ok(combo != 0, "Failed to create combobox window\n");
6925 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
6926 ok(ret == 0, "expected 0, got %ld\n", ret);
6928 cbInfo.cbSize = sizeof(COMBOBOXINFO);
6929 SetLastError(0xdeadbeef);
6930 res = pGetComboBoxInfo(combo, &cbInfo);
6931 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
6932 lbox = cbInfo.hwndList;
6933 lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
6934 (ULONG_PTR)combobox_lbox_subclass_proc);
6935 flush_sequence();
6937 log_all_parent_messages++;
6938 SendMessageA(combo, CB_SETCURSEL, 0, 0);
6939 log_all_parent_messages--;
6940 ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
6942 DestroyWindow(combo);
6943 DestroyWindow(parent);
6946 /****************** WM_IME_KEYDOWN message test *******************/
6948 static const struct message WmImeKeydownMsgSeq_0[] =
6950 { WM_IME_KEYDOWN, wparam, VK_RETURN },
6951 { WM_CHAR, wparam, 'A' },
6952 { 0 }
6955 static const struct message WmImeKeydownMsgSeq_1[] =
6957 { WM_KEYDOWN, optional|wparam, VK_RETURN },
6958 { WM_CHAR, optional|wparam, VK_RETURN },
6959 { 0 }
6962 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6964 struct recvd_message msg;
6966 msg.hwnd = hwnd;
6967 msg.message = message;
6968 msg.flags = wparam|lparam;
6969 msg.wParam = wParam;
6970 msg.lParam = lParam;
6971 msg.descr = "wmime_keydown";
6972 add_message(&msg);
6974 return DefWindowProcA(hwnd, message, wParam, lParam);
6977 static void register_wmime_keydown_class(void)
6979 WNDCLASSA cls;
6981 ZeroMemory(&cls, sizeof(WNDCLASSA));
6982 cls.lpfnWndProc = wmime_keydown_procA;
6983 cls.hInstance = GetModuleHandleA(0);
6984 cls.lpszClassName = "wmime_keydown_class";
6985 if (!RegisterClassA(&cls)) assert(0);
6988 static void test_wmime_keydown_message(void)
6990 HWND hwnd;
6991 MSG msg;
6993 trace("Message sequences by WM_IME_KEYDOWN\n");
6995 register_wmime_keydown_class();
6996 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
6997 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6998 NULL, NULL, 0);
6999 flush_events();
7000 flush_sequence();
7002 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7003 SendMessageA(hwnd, WM_CHAR, 'A', 1);
7004 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7006 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7008 TranslateMessage(&msg);
7009 DispatchMessageA(&msg);
7011 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7013 DestroyWindow(hwnd);
7016 /************* painting message test ********************/
7018 void dump_region(HRGN hrgn)
7020 DWORD i, size;
7021 RGNDATA *data = NULL;
7022 RECT *rect;
7024 if (!hrgn)
7026 printf( "null region\n" );
7027 return;
7029 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7030 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7031 GetRegionData( hrgn, size, data );
7032 printf("%d rects:", data->rdh.nCount );
7033 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7034 printf( " %s", wine_dbgstr_rect( rect ));
7035 printf("\n");
7036 HeapFree( GetProcessHeap(), 0, data );
7039 static void check_update_rgn( HWND hwnd, HRGN hrgn )
7041 INT ret;
7042 RECT r1, r2;
7043 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7044 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7046 ret = GetUpdateRgn( hwnd, update, FALSE );
7047 ok( ret != ERROR, "GetUpdateRgn failed\n" );
7048 if (ret == NULLREGION)
7050 ok( !hrgn, "Update region shouldn't be empty\n" );
7052 else
7054 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7056 ok( 0, "Regions are different\n" );
7057 if (winetest_debug > 0)
7059 printf( "Update region: " );
7060 dump_region( update );
7061 printf( "Wanted region: " );
7062 dump_region( hrgn );
7066 GetRgnBox( update, &r1 );
7067 GetUpdateRect( hwnd, &r2, FALSE );
7068 ok( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", wine_dbgstr_rect( &r1 ),
7069 wine_dbgstr_rect( &r2 ));
7071 DeleteObject( tmp );
7072 DeleteObject( update );
7075 static const struct message WmInvalidateRgn[] = {
7076 { WM_NCPAINT, sent },
7077 { WM_GETTEXT, sent|defwinproc|optional },
7078 { 0 }
7081 static const struct message WmGetUpdateRect[] = {
7082 { WM_NCPAINT, sent },
7083 { WM_GETTEXT, sent|defwinproc|optional },
7084 { WM_PAINT, sent },
7085 { 0 }
7088 static const struct message WmInvalidateFull[] = {
7089 { WM_NCPAINT, sent|wparam, 1 },
7090 { WM_GETTEXT, sent|defwinproc|optional },
7091 { 0 }
7094 static const struct message WmInvalidateErase[] = {
7095 { WM_NCPAINT, sent|wparam, 1 },
7096 { WM_GETTEXT, sent|defwinproc|optional },
7097 { WM_ERASEBKGND, sent },
7098 { 0 }
7101 static const struct message WmInvalidatePaint[] = {
7102 { WM_PAINT, sent },
7103 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7104 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7105 { 0 }
7108 static const struct message WmInvalidateErasePaint[] = {
7109 { WM_PAINT, sent },
7110 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7111 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7112 { WM_ERASEBKGND, sent|beginpaint|optional },
7113 { 0 }
7116 static const struct message WmInvalidateErasePaint2[] = {
7117 { WM_PAINT, sent },
7118 { WM_NCPAINT, sent|beginpaint },
7119 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7120 { WM_ERASEBKGND, sent|beginpaint|optional },
7121 { 0 }
7124 static const struct message WmErase[] = {
7125 { WM_ERASEBKGND, sent },
7126 { 0 }
7129 static const struct message WmPaint[] = {
7130 { WM_PAINT, sent },
7131 { 0 }
7134 static const struct message WmParentOnlyPaint[] = {
7135 { WM_PAINT, sent|parent },
7136 { 0 }
7139 static const struct message WmInvalidateParent[] = {
7140 { WM_NCPAINT, sent|parent },
7141 { WM_GETTEXT, sent|defwinproc|parent|optional },
7142 { WM_ERASEBKGND, sent|parent },
7143 { 0 }
7146 static const struct message WmInvalidateParentChild[] = {
7147 { WM_NCPAINT, sent|parent },
7148 { WM_GETTEXT, sent|defwinproc|parent|optional },
7149 { WM_ERASEBKGND, sent|parent },
7150 { WM_NCPAINT, sent },
7151 { WM_GETTEXT, sent|defwinproc|optional },
7152 { WM_ERASEBKGND, sent },
7153 { 0 }
7156 static const struct message WmInvalidateParentChild2[] = {
7157 { WM_ERASEBKGND, sent|parent },
7158 { WM_NCPAINT, sent },
7159 { WM_GETTEXT, sent|defwinproc|optional },
7160 { WM_ERASEBKGND, sent },
7161 { 0 }
7164 static const struct message WmParentPaint[] = {
7165 { WM_PAINT, sent|parent },
7166 { WM_PAINT, sent },
7167 { 0 }
7170 static const struct message WmParentPaintNc[] = {
7171 { WM_PAINT, sent|parent },
7172 { WM_PAINT, sent },
7173 { WM_NCPAINT, sent|beginpaint },
7174 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7175 { WM_ERASEBKGND, sent|beginpaint|optional },
7176 { 0 }
7179 static const struct message WmChildPaintNc[] = {
7180 { WM_PAINT, sent },
7181 { WM_NCPAINT, sent|beginpaint },
7182 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7183 { WM_ERASEBKGND, sent|beginpaint|optional },
7184 { 0 }
7187 static const struct message WmParentErasePaint[] = {
7188 { WM_PAINT, sent|parent },
7189 { WM_NCPAINT, sent|parent|beginpaint },
7190 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7191 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7192 { WM_PAINT, sent },
7193 { WM_NCPAINT, sent|beginpaint },
7194 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7195 { WM_ERASEBKGND, sent|beginpaint|optional },
7196 { 0 }
7199 static const struct message WmParentOnlyNcPaint[] = {
7200 { WM_PAINT, sent|parent },
7201 { WM_NCPAINT, sent|parent|beginpaint },
7202 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7203 { 0 }
7206 static const struct message WmSetParentStyle[] = {
7207 { WM_STYLECHANGING, sent|parent },
7208 { WM_STYLECHANGED, sent|parent },
7209 { 0 }
7212 static void test_paint_messages(void)
7214 BOOL ret;
7215 RECT rect, rect2;
7216 POINT pt;
7217 MSG msg;
7218 HWND hparent, hchild;
7219 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7220 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7221 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7222 100, 100, 200, 200, 0, 0, 0, NULL);
7223 ok (hwnd != 0, "Failed to create overlapped window\n");
7225 ShowWindow( hwnd, SW_SHOW );
7226 UpdateWindow( hwnd );
7227 flush_events();
7228 flush_sequence();
7230 check_update_rgn( hwnd, 0 );
7231 SetRectRgn( hrgn, 10, 10, 20, 20 );
7232 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7233 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7234 check_update_rgn( hwnd, hrgn );
7235 SetRectRgn( hrgn2, 20, 20, 30, 30 );
7236 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7237 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7238 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7239 check_update_rgn( hwnd, hrgn );
7240 /* validate everything */
7241 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7242 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7243 check_update_rgn( hwnd, 0 );
7245 /* test empty region */
7246 SetRectRgn( hrgn, 10, 10, 10, 15 );
7247 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7248 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7249 check_update_rgn( hwnd, 0 );
7250 /* test empty rect */
7251 SetRect( &rect, 10, 10, 10, 15 );
7252 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7253 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7254 check_update_rgn( hwnd, 0 );
7256 /* flush pending messages */
7257 flush_events();
7258 flush_sequence();
7260 GetClientRect( hwnd, &rect );
7261 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7262 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7263 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7265 trace("testing InvalidateRect(0, NULL, FALSE)\n");
7266 SetRectEmpty( &rect );
7267 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
7268 check_update_rgn( hwnd, hrgn );
7269 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7270 flush_events();
7271 ok_sequence( WmPaint, "Paint", FALSE );
7272 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7273 check_update_rgn( hwnd, 0 );
7275 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
7276 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7278 trace("testing ValidateRect(0, NULL)\n");
7279 SetRectEmpty( &rect );
7280 if (ValidateRect(0, &rect) && /* not supported on Win9x */
7281 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
7283 check_update_rgn( hwnd, hrgn );
7284 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7285 flush_events();
7286 ok_sequence( WmPaint, "Paint", FALSE );
7287 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7288 check_update_rgn( hwnd, 0 );
7291 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
7292 SetLastError(0xdeadbeef);
7293 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
7294 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
7295 "wrong error code %d\n", GetLastError());
7296 check_update_rgn( hwnd, 0 );
7297 flush_events();
7298 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7300 trace("testing ValidateRgn(0, NULL)\n");
7301 SetLastError(0xdeadbeef);
7302 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
7303 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7304 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7305 "wrong error code %d\n", GetLastError());
7306 check_update_rgn( hwnd, 0 );
7307 flush_events();
7308 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7310 trace("testing UpdateWindow(NULL)\n");
7311 SetLastError(0xdeadbeef);
7312 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
7313 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7314 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7315 "wrong error code %d\n", GetLastError());
7316 check_update_rgn( hwnd, 0 );
7317 flush_events();
7318 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7320 /* now with frame */
7321 SetRectRgn( hrgn, -5, -5, 20, 20 );
7323 /* flush pending messages */
7324 flush_events();
7325 flush_sequence();
7326 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7327 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7329 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
7330 check_update_rgn( hwnd, hrgn );
7332 flush_sequence();
7333 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7334 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7336 flush_sequence();
7337 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7338 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
7340 GetClientRect( hwnd, &rect );
7341 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7342 check_update_rgn( hwnd, hrgn );
7344 flush_sequence();
7345 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
7346 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7348 flush_sequence();
7349 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
7350 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
7351 check_update_rgn( hwnd, 0 );
7353 flush_sequence();
7354 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
7355 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
7356 check_update_rgn( hwnd, 0 );
7358 flush_sequence();
7359 SetRectRgn( hrgn, 0, 0, 100, 100 );
7360 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7361 SetRectRgn( hrgn, 0, 0, 50, 100 );
7362 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
7363 SetRectRgn( hrgn, 50, 0, 100, 100 );
7364 check_update_rgn( hwnd, hrgn );
7365 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7366 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
7367 check_update_rgn( hwnd, 0 );
7369 flush_sequence();
7370 SetRectRgn( hrgn, 0, 0, 100, 100 );
7371 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7372 SetRectRgn( hrgn, 0, 0, 100, 50 );
7373 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7374 ok_sequence( WmErase, "Erase", FALSE );
7375 SetRectRgn( hrgn, 0, 50, 100, 100 );
7376 check_update_rgn( hwnd, hrgn );
7378 flush_sequence();
7379 SetRectRgn( hrgn, 0, 0, 100, 100 );
7380 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7381 SetRectRgn( hrgn, 0, 0, 50, 50 );
7382 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
7383 ok_sequence( WmPaint, "Paint", FALSE );
7385 flush_sequence();
7386 SetRectRgn( hrgn, -4, -4, -2, -2 );
7387 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7388 SetRectRgn( hrgn, -200, -200, -198, -198 );
7389 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
7390 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7392 flush_sequence();
7393 SetRectRgn( hrgn, -4, -4, -2, -2 );
7394 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7395 SetRectRgn( hrgn, -4, -4, -3, -3 );
7396 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
7397 SetRectRgn( hrgn, 0, 0, 1, 1 );
7398 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
7399 ok_sequence( WmPaint, "Paint", FALSE );
7401 flush_sequence();
7402 SetRectRgn( hrgn, -4, -4, -1, -1 );
7403 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7404 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
7405 /* make sure no WM_PAINT was generated */
7406 flush_events();
7407 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7409 flush_sequence();
7410 SetRectRgn( hrgn, -4, -4, -1, -1 );
7411 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7412 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
7414 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
7416 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
7417 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
7418 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
7419 ret = GetUpdateRect( hwnd, &rect, FALSE );
7420 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
7421 /* this will send WM_NCPAINT and validate the non client area */
7422 ret = GetUpdateRect( hwnd, &rect, TRUE );
7423 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
7425 DispatchMessageA( &msg );
7427 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
7429 DestroyWindow( hwnd );
7431 /* now test with a child window */
7433 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
7434 100, 100, 200, 200, 0, 0, 0, NULL);
7435 ok (hparent != 0, "Failed to create parent window\n");
7437 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
7438 10, 10, 100, 100, hparent, 0, 0, NULL);
7439 ok (hchild != 0, "Failed to create child window\n");
7441 ShowWindow( hparent, SW_SHOW );
7442 UpdateWindow( hparent );
7443 UpdateWindow( hchild );
7444 flush_events();
7445 flush_sequence();
7446 log_all_parent_messages++;
7448 SetRect( &rect, 0, 0, 50, 50 );
7449 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7450 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7451 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
7453 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7454 pt.x = pt.y = 0;
7455 MapWindowPoints( hchild, hparent, &pt, 1 );
7456 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
7457 check_update_rgn( hchild, hrgn );
7458 SetRectRgn( hrgn, 0, 0, 50, 50 );
7459 check_update_rgn( hparent, hrgn );
7460 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7461 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
7462 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7463 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7465 flush_events();
7466 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
7468 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7469 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7470 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
7471 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7472 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7474 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7475 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7476 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
7478 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
7479 flush_sequence();
7480 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7481 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7482 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
7484 /* flush all paint messages */
7485 flush_events();
7486 flush_sequence();
7488 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
7489 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7490 SetRectRgn( hrgn, 0, 0, 50, 50 );
7491 check_update_rgn( hparent, hrgn );
7492 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7493 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7494 SetRectRgn( hrgn, 0, 0, 50, 50 );
7495 check_update_rgn( hparent, hrgn );
7497 /* flush all paint messages */
7498 flush_events();
7499 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
7500 flush_sequence();
7502 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
7503 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7504 SetRectRgn( hrgn, 0, 0, 50, 50 );
7505 check_update_rgn( hparent, hrgn );
7506 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7507 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7508 SetRectRgn( hrgn2, 10, 10, 50, 50 );
7509 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
7510 check_update_rgn( hparent, hrgn );
7511 /* flush all paint messages */
7512 flush_events();
7513 flush_sequence();
7515 /* same as above but parent gets completely validated */
7516 SetRect( &rect, 20, 20, 30, 30 );
7517 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7518 SetRectRgn( hrgn, 20, 20, 30, 30 );
7519 check_update_rgn( hparent, hrgn );
7520 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7521 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7522 check_update_rgn( hparent, 0 ); /* no update region */
7523 flush_events();
7524 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
7526 /* make sure RDW_VALIDATE on child doesn't have the same effect */
7527 flush_sequence();
7528 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7529 SetRectRgn( hrgn, 20, 20, 30, 30 );
7530 check_update_rgn( hparent, hrgn );
7531 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
7532 SetRectRgn( hrgn, 20, 20, 30, 30 );
7533 check_update_rgn( hparent, hrgn );
7535 /* same as above but normal WM_PAINT doesn't validate parent */
7536 flush_sequence();
7537 SetRect( &rect, 20, 20, 30, 30 );
7538 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7539 SetRectRgn( hrgn, 20, 20, 30, 30 );
7540 check_update_rgn( hparent, hrgn );
7541 /* no WM_PAINT in child while parent still pending */
7542 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7543 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
7544 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7545 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
7547 flush_sequence();
7548 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7549 /* no WM_PAINT in child while parent still pending */
7550 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7551 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
7552 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
7553 /* now that parent is valid child should get WM_PAINT */
7554 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7555 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7556 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7557 ok_sequence( WmEmptySeq, "No other message", FALSE );
7559 /* same thing with WS_CLIPCHILDREN in parent */
7560 flush_sequence();
7561 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
7562 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
7563 /* changing style invalidates non client area, but we need to invalidate something else to see it */
7564 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
7565 ok_sequence( WmEmptySeq, "No message", FALSE );
7566 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
7567 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
7569 flush_sequence();
7570 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
7571 SetRectRgn( hrgn, 20, 20, 30, 30 );
7572 check_update_rgn( hparent, hrgn );
7573 /* no WM_PAINT in child while parent still pending */
7574 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7575 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
7576 /* WM_PAINT in parent first */
7577 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7578 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
7580 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
7581 flush_sequence();
7582 SetRect( &rect, 0, 0, 30, 30 );
7583 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
7584 SetRectRgn( hrgn, 0, 0, 30, 30 );
7585 check_update_rgn( hparent, hrgn );
7586 flush_events();
7587 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
7589 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
7590 flush_sequence();
7591 SetRect( &rect, -10, 0, 30, 30 );
7592 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
7593 SetRect( &rect, 0, 0, 20, 20 );
7594 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
7595 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
7596 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
7598 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
7599 flush_sequence();
7600 SetRect( &rect, -10, 0, 30, 30 );
7601 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
7602 SetRect( &rect, 0, 0, 100, 100 );
7603 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
7604 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
7605 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
7606 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7607 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
7609 /* WS_CLIPCHILDREN doesn't exclude children from update region */
7610 flush_sequence();
7611 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
7612 GetClientRect( hparent, &rect );
7613 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7614 check_update_rgn( hparent, hrgn );
7615 flush_events();
7617 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
7618 GetClientRect( hparent, &rect );
7619 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7620 check_update_rgn( hparent, hrgn );
7621 flush_events();
7623 /* test RDW_INTERNALPAINT behavior */
7625 flush_sequence();
7626 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
7627 flush_events();
7628 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
7630 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
7631 flush_events();
7632 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
7634 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
7635 flush_events();
7636 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
7638 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
7639 UpdateWindow( hparent );
7640 flush_events();
7641 flush_sequence();
7642 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
7643 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7644 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
7645 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7646 flush_events();
7647 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
7649 UpdateWindow( hparent );
7650 flush_events();
7651 flush_sequence();
7652 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
7653 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7654 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
7655 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7656 flush_events();
7657 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
7659 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
7660 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
7661 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
7662 flush_events();
7663 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
7665 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
7666 UpdateWindow( hparent );
7667 flush_events();
7668 flush_sequence();
7669 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
7670 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7671 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
7672 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7673 flush_events();
7674 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
7676 UpdateWindow( hparent );
7677 flush_events();
7678 flush_sequence();
7679 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
7680 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7681 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
7682 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7683 flush_events();
7684 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
7686 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
7687 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
7689 UpdateWindow( hparent );
7690 flush_events();
7691 flush_sequence();
7692 trace("testing SetWindowPos(-10000, -10000) on child\n");
7693 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
7694 check_update_rgn( hchild, 0 );
7695 flush_events();
7697 #if 0 /* this one doesn't pass under Wine yet */
7698 UpdateWindow( hparent );
7699 flush_events();
7700 flush_sequence();
7701 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
7702 ShowWindow( hchild, SW_MINIMIZE );
7703 check_update_rgn( hchild, 0 );
7704 flush_events();
7705 #endif
7707 UpdateWindow( hparent );
7708 flush_events();
7709 flush_sequence();
7710 trace("testing SetWindowPos(-10000, -10000) on parent\n");
7711 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
7712 check_update_rgn( hparent, 0 );
7713 flush_events();
7715 log_all_parent_messages--;
7716 DestroyWindow( hparent );
7717 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
7719 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
7721 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
7722 100, 100, 200, 200, 0, 0, 0, NULL);
7723 ok (hparent != 0, "Failed to create parent window\n");
7725 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
7726 10, 10, 100, 100, hparent, 0, 0, NULL);
7727 ok (hchild != 0, "Failed to create child window\n");
7729 ShowWindow( hparent, SW_SHOW );
7730 UpdateWindow( hparent );
7731 UpdateWindow( hchild );
7732 flush_events();
7733 flush_sequence();
7735 /* moving child outside of parent boundaries changes update region */
7736 SetRect( &rect, 0, 0, 40, 40 );
7737 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7738 SetRectRgn( hrgn, 0, 0, 40, 40 );
7739 check_update_rgn( hchild, hrgn );
7740 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
7741 SetRectRgn( hrgn, 10, 0, 40, 40 );
7742 check_update_rgn( hchild, hrgn );
7743 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
7744 SetRectRgn( hrgn, 10, 10, 40, 40 );
7745 check_update_rgn( hchild, hrgn );
7747 /* moving parent off-screen does too */
7748 SetRect( &rect, 0, 0, 100, 100 );
7749 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
7750 SetRectRgn( hrgn, 0, 0, 100, 100 );
7751 check_update_rgn( hparent, hrgn );
7752 SetRectRgn( hrgn, 10, 10, 40, 40 );
7753 check_update_rgn( hchild, hrgn );
7754 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
7755 GetUpdateRect( hparent, &rect2, FALSE );
7756 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
7758 rect.left += 20;
7759 rect.top += 20;
7761 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7762 check_update_rgn( hparent, hrgn );
7763 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
7764 check_update_rgn( hchild, hrgn );
7766 /* invalidated region is cropped by the parent rects */
7767 SetRect( &rect, 0, 0, 50, 50 );
7768 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7769 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
7770 check_update_rgn( hchild, hrgn );
7772 DestroyWindow( hparent );
7773 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
7774 flush_sequence();
7776 DeleteObject( hrgn );
7777 DeleteObject( hrgn2 );
7780 struct wnd_event
7782 HWND hwnd;
7783 HANDLE grand_child;
7784 HANDLE start_event;
7785 HANDLE stop_event;
7788 static DWORD WINAPI thread_proc(void *param)
7790 MSG msg;
7791 struct wnd_event *wnd_event = param;
7793 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
7794 100, 100, 200, 200, 0, 0, 0, NULL);
7795 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
7797 SetEvent(wnd_event->start_event);
7799 while (GetMessageA(&msg, 0, 0, 0))
7801 TranslateMessage(&msg);
7802 DispatchMessageA(&msg);
7805 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
7807 return 0;
7810 static DWORD CALLBACK create_grand_child_thread( void *param )
7812 struct wnd_event *wnd_event = param;
7813 HWND hchild;
7814 MSG msg;
7816 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
7817 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
7818 ok (hchild != 0, "Failed to create child window\n");
7819 flush_events();
7820 flush_sequence();
7821 SetEvent( wnd_event->start_event );
7823 for (;;)
7825 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
7826 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
7827 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7829 return 0;
7832 static DWORD CALLBACK create_child_thread( void *param )
7834 struct wnd_event *wnd_event = param;
7835 struct wnd_event child_event;
7836 DWORD ret, tid;
7837 MSG msg;
7839 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
7840 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
7841 ok (child_event.hwnd != 0, "Failed to create child window\n");
7842 SetFocus( child_event.hwnd );
7843 flush_events();
7844 flush_sequence();
7845 child_event.start_event = wnd_event->start_event;
7846 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
7847 for (;;)
7849 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
7850 if (ret != 1) break;
7851 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7853 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
7854 ok( !ret, "WaitForSingleObject failed %x\n", ret );
7855 return 0;
7858 static const char manifest_dep[] =
7859 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
7860 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
7861 " <file name=\"testdep.dll\" />"
7862 "</assembly>";
7864 static const char manifest_main[] =
7865 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
7866 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
7867 "<dependency>"
7868 " <dependentAssembly>"
7869 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
7870 " </dependentAssembly>"
7871 "</dependency>"
7872 "</assembly>";
7874 static void create_manifest_file(const char *filename, const char *manifest)
7876 WCHAR path[MAX_PATH];
7877 HANDLE file;
7878 DWORD size;
7880 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
7881 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7882 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
7883 WriteFile(file, manifest, strlen(manifest), &size, NULL);
7884 CloseHandle(file);
7887 static HANDLE test_create(const char *file)
7889 WCHAR path[MAX_PATH];
7890 ACTCTXW actctx;
7891 HANDLE handle;
7893 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
7894 memset(&actctx, 0, sizeof(ACTCTXW));
7895 actctx.cbSize = sizeof(ACTCTXW);
7896 actctx.lpSource = path;
7898 handle = pCreateActCtxW(&actctx);
7899 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
7901 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
7902 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
7903 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
7904 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
7905 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
7906 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
7907 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
7908 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
7909 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
7911 return handle;
7914 static void test_interthread_messages(void)
7916 HANDLE hThread, context, handle, event;
7917 ULONG_PTR cookie;
7918 DWORD tid;
7919 WNDPROC proc;
7920 MSG msg;
7921 char buf[256];
7922 int len, expected_len;
7923 struct wnd_event wnd_event;
7924 BOOL ret;
7926 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
7927 if (!wnd_event.start_event)
7929 win_skip("skipping interthread message test under win9x\n");
7930 return;
7933 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
7934 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
7936 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7938 CloseHandle(wnd_event.start_event);
7940 SetLastError(0xdeadbeef);
7941 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
7942 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
7943 "wrong error code %d\n", GetLastError());
7945 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
7946 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
7948 expected_len = lstrlenA("window caption text");
7949 memset(buf, 0, sizeof(buf));
7950 SetLastError(0xdeadbeef);
7951 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
7952 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
7953 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
7955 msg.hwnd = wnd_event.hwnd;
7956 msg.message = WM_GETTEXT;
7957 msg.wParam = sizeof(buf);
7958 msg.lParam = (LPARAM)buf;
7959 memset(buf, 0, sizeof(buf));
7960 SetLastError(0xdeadbeef);
7961 len = DispatchMessageA(&msg);
7962 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
7963 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
7965 /* the following test causes an exception in user.exe under win9x */
7966 msg.hwnd = wnd_event.hwnd;
7967 msg.message = WM_TIMER;
7968 msg.wParam = 0;
7969 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
7970 SetLastError(0xdeadbeef);
7971 len = DispatchMessageA(&msg);
7972 ok(!len && GetLastError() == 0xdeadbeef,
7973 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
7975 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
7976 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
7978 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7979 CloseHandle(hThread);
7981 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
7983 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7984 100, 100, 200, 200, 0, 0, 0, NULL);
7985 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
7986 flush_events();
7987 flush_sequence();
7988 log_all_parent_messages++;
7989 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
7990 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
7991 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
7992 for (;;)
7994 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
7995 if (ret != 1) break;
7996 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7998 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
7999 /* now wait for the thread without processing messages; this shouldn't deadlock */
8000 SetEvent( wnd_event.stop_event );
8001 ret = WaitForSingleObject( hThread, 5000 );
8002 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8003 CloseHandle( hThread );
8005 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8006 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8007 CloseHandle( wnd_event.grand_child );
8009 CloseHandle( wnd_event.start_event );
8010 CloseHandle( wnd_event.stop_event );
8011 flush_events();
8012 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8013 log_all_parent_messages--;
8014 DestroyWindow( wnd_event.hwnd );
8016 /* activation context tests */
8017 if (!pActivateActCtx)
8019 win_skip("Activation contexts are not supported, skipping\n");
8020 return;
8023 create_manifest_file("testdep1.manifest", manifest_dep);
8024 create_manifest_file("main.manifest", manifest_main);
8026 context = test_create("main.manifest");
8027 DeleteFileA("testdep1.manifest");
8028 DeleteFileA("main.manifest");
8030 handle = (void*)0xdeadbeef;
8031 ret = pGetCurrentActCtx(&handle);
8032 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8033 ok(handle == 0, "active context %p\n", handle);
8035 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8036 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8037 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8038 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8039 CloseHandle(wnd_event.start_event);
8041 /* context is activated after thread creation, so it doesn't inherit it by default */
8042 ret = pActivateActCtx(context, &cookie);
8043 ok(ret, "activation failed: %u\n", GetLastError());
8045 handle = 0;
8046 ret = pGetCurrentActCtx(&handle);
8047 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8048 ok(handle != 0, "active context %p\n", handle);
8049 pReleaseActCtx(handle);
8051 /* destination window will test for active context */
8052 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8053 ok(ret, "thread window returned %d\n", ret);
8055 event = CreateEventW(NULL, 0, 0, NULL);
8056 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8057 ok(ret, "thread window returned %d\n", ret);
8058 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8059 CloseHandle(event);
8061 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8062 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8064 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8065 CloseHandle(hThread);
8067 ret = pDeactivateActCtx(0, cookie);
8068 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8069 pReleaseActCtx(context);
8073 static const struct message WmVkN[] = {
8074 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8075 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8076 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8077 { WM_CHAR, wparam|lparam, 'n', 1 },
8078 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8079 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8080 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8081 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8082 { 0 }
8084 static const struct message WmShiftVkN[] = {
8085 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8086 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8087 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8088 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8089 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8090 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8091 { WM_CHAR, wparam|lparam, 'N', 1 },
8092 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8093 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8094 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8095 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8096 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8097 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8098 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8099 { 0 }
8101 static const struct message WmCtrlVkN[] = {
8102 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8103 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8104 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8105 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8106 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8107 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8108 { WM_CHAR, wparam|lparam, 0x000e, 1 },
8109 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8110 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8111 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8112 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8113 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8114 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8115 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8116 { 0 }
8118 static const struct message WmCtrlVkN_2[] = {
8119 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8120 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8121 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8122 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8123 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8124 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8125 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8126 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8127 { WM_KEYUP, sent|wparam|lparam, 'N', 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 WmAltVkN[] = {
8134 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8135 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8136 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8137 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8138 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8139 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8140 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8141 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8142 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8143 { HCBT_SYSCOMMAND, hook },
8144 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8145 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8146 { 0x00AE, sent|defwinproc|optional }, /* XP */
8147 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8148 { WM_INITMENU, sent|defwinproc },
8149 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8150 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8151 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8152 { WM_CAPTURECHANGED, sent|defwinproc },
8153 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8154 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8155 { WM_EXITMENULOOP, sent|defwinproc },
8156 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8157 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8158 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8159 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8160 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8161 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8162 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8163 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8164 { 0 }
8166 static const struct message WmAltVkN_2[] = {
8167 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8168 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8169 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8170 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8171 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8172 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8173 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8174 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8175 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8176 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8177 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8178 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8179 { 0 }
8181 static const struct message WmCtrlAltVkN[] = {
8182 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8183 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8184 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8185 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8186 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8187 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8188 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8189 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8190 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8191 { WM_CHAR, optional },
8192 { WM_CHAR, sent|optional },
8193 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8194 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8195 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8196 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8197 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8198 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8199 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8200 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8201 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8202 { 0 }
8204 static const struct message WmCtrlShiftVkN[] = {
8205 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8206 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8207 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8208 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8209 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8210 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8211 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8212 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8213 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8214 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8215 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8216 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8217 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8218 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8219 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8220 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8221 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8222 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8223 { 0 }
8225 static const struct message WmCtrlAltShiftVkN[] = {
8226 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8227 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8228 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8229 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8230 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8231 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8232 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8233 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8234 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8235 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8236 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8237 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8238 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8239 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8240 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8241 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8242 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8243 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8244 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8245 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8246 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8247 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8248 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8249 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8250 { 0 }
8252 static const struct message WmAltPressRelease[] = {
8253 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8254 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8255 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8256 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8257 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8258 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8259 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
8260 { HCBT_SYSCOMMAND, hook },
8261 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8262 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8263 { WM_INITMENU, sent|defwinproc },
8264 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8265 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8266 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8268 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
8270 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8271 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8272 { WM_CAPTURECHANGED, sent|defwinproc },
8273 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8274 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8275 { WM_EXITMENULOOP, sent|defwinproc },
8276 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8277 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8278 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8279 { 0 }
8281 static const struct message WmShiftMouseButton[] = {
8282 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8283 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8284 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8285 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
8286 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
8287 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
8288 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
8289 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
8290 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
8291 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8292 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8293 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8294 { 0 }
8296 static const struct message WmF1Seq[] = {
8297 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
8298 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
8299 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
8300 { WM_KEYF1, wparam|lparam, 0, 0 },
8301 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
8302 { WM_HELP, sent|defwinproc },
8303 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
8304 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
8305 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
8306 { 0 }
8308 static const struct message WmVkAppsSeq[] = {
8309 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
8310 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
8311 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
8312 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
8313 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
8314 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
8315 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
8316 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
8317 { 0 }
8319 static const struct message WmVkF10Seq[] = {
8320 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8321 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8322 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8323 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8324 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8325 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8326 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8327 { HCBT_SYSCOMMAND, hook },
8328 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8329 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8330 { WM_INITMENU, sent|defwinproc },
8331 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8332 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8333 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8335 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
8337 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8338 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8339 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8340 { WM_CAPTURECHANGED, sent|defwinproc },
8341 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8342 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8343 { WM_EXITMENULOOP, sent|defwinproc },
8344 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8345 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8346 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8347 { 0 }
8349 static const struct message WmShiftF10Seq[] = {
8350 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8351 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8352 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
8353 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8354 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8355 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8356 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
8357 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8358 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8359 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8360 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8361 { HCBT_SYSCOMMAND, hook },
8362 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8363 { WM_INITMENU, sent|defwinproc },
8364 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8365 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
8366 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
8367 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
8368 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
8369 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8370 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
8371 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
8372 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
8373 { 0 }
8376 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
8378 MSG msg;
8380 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
8382 struct recvd_message log_msg;
8384 /* ignore some unwanted messages */
8385 if (msg.message == WM_MOUSEMOVE ||
8386 msg.message == WM_TIMER ||
8387 ignore_message( msg.message ))
8388 continue;
8390 log_msg.hwnd = msg.hwnd;
8391 log_msg.message = msg.message;
8392 log_msg.flags = wparam|lparam;
8393 log_msg.wParam = msg.wParam;
8394 log_msg.lParam = msg.lParam;
8395 log_msg.descr = "accel";
8396 add_message(&log_msg);
8398 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
8400 TranslateMessage(&msg);
8401 DispatchMessageA(&msg);
8406 static void test_accelerators(void)
8408 RECT rc;
8409 POINT pt;
8410 SHORT state;
8411 HACCEL hAccel;
8412 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8413 100, 100, 200, 200, 0, 0, 0, NULL);
8414 BOOL ret;
8416 assert(hwnd != 0);
8417 UpdateWindow(hwnd);
8418 flush_events();
8419 flush_sequence();
8421 SetFocus(hwnd);
8422 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
8424 state = GetKeyState(VK_SHIFT);
8425 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
8426 state = GetKeyState(VK_CAPITAL);
8427 ok(state == 0, "wrong CapsLock state %04x\n", state);
8429 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
8430 assert(hAccel != 0);
8432 flush_events();
8433 pump_msg_loop(hwnd, 0);
8434 flush_sequence();
8436 trace("testing VK_N press/release\n");
8437 flush_sequence();
8438 keybd_event('N', 0, 0, 0);
8439 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8440 pump_msg_loop(hwnd, hAccel);
8441 if (!sequence_cnt) /* we didn't get any message */
8443 skip( "queuing key events not supported\n" );
8444 goto done;
8446 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8448 trace("testing Shift+VK_N press/release\n");
8449 flush_sequence();
8450 keybd_event(VK_SHIFT, 0, 0, 0);
8451 keybd_event('N', 0, 0, 0);
8452 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8453 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8454 pump_msg_loop(hwnd, hAccel);
8455 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8457 trace("testing Ctrl+VK_N press/release\n");
8458 flush_sequence();
8459 keybd_event(VK_CONTROL, 0, 0, 0);
8460 keybd_event('N', 0, 0, 0);
8461 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8462 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8463 pump_msg_loop(hwnd, hAccel);
8464 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
8466 trace("testing Alt+VK_N press/release\n");
8467 flush_sequence();
8468 keybd_event(VK_MENU, 0, 0, 0);
8469 keybd_event('N', 0, 0, 0);
8470 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8471 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8472 pump_msg_loop(hwnd, hAccel);
8473 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
8475 trace("testing Ctrl+Alt+VK_N press/release 1\n");
8476 flush_sequence();
8477 keybd_event(VK_CONTROL, 0, 0, 0);
8478 keybd_event(VK_MENU, 0, 0, 0);
8479 keybd_event('N', 0, 0, 0);
8480 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8481 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8482 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8483 pump_msg_loop(hwnd, hAccel);
8484 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
8486 ret = DestroyAcceleratorTable(hAccel);
8487 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
8489 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
8490 assert(hAccel != 0);
8492 trace("testing VK_N press/release\n");
8493 flush_sequence();
8494 keybd_event('N', 0, 0, 0);
8495 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8496 pump_msg_loop(hwnd, hAccel);
8497 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8499 trace("testing Shift+VK_N press/release\n");
8500 flush_sequence();
8501 keybd_event(VK_SHIFT, 0, 0, 0);
8502 keybd_event('N', 0, 0, 0);
8503 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8504 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8505 pump_msg_loop(hwnd, hAccel);
8506 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8508 trace("testing Ctrl+VK_N press/release 2\n");
8509 flush_sequence();
8510 keybd_event(VK_CONTROL, 0, 0, 0);
8511 keybd_event('N', 0, 0, 0);
8512 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8513 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8514 pump_msg_loop(hwnd, hAccel);
8515 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
8517 trace("testing Alt+VK_N press/release 2\n");
8518 flush_sequence();
8519 keybd_event(VK_MENU, 0, 0, 0);
8520 keybd_event('N', 0, 0, 0);
8521 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8522 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8523 pump_msg_loop(hwnd, hAccel);
8524 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
8526 trace("testing Ctrl+Alt+VK_N press/release 2\n");
8527 flush_sequence();
8528 keybd_event(VK_CONTROL, 0, 0, 0);
8529 keybd_event(VK_MENU, 0, 0, 0);
8530 keybd_event('N', 0, 0, 0);
8531 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8532 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8533 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8534 pump_msg_loop(hwnd, hAccel);
8535 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
8537 trace("testing Ctrl+Shift+VK_N press/release\n");
8538 flush_sequence();
8539 keybd_event(VK_CONTROL, 0, 0, 0);
8540 keybd_event(VK_SHIFT, 0, 0, 0);
8541 keybd_event('N', 0, 0, 0);
8542 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8543 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8544 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8545 pump_msg_loop(hwnd, hAccel);
8546 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
8548 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
8549 flush_sequence();
8550 keybd_event(VK_CONTROL, 0, 0, 0);
8551 keybd_event(VK_MENU, 0, 0, 0);
8552 keybd_event(VK_SHIFT, 0, 0, 0);
8553 keybd_event('N', 0, 0, 0);
8554 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8555 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8556 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8557 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8558 pump_msg_loop(hwnd, hAccel);
8559 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
8561 ret = DestroyAcceleratorTable(hAccel);
8562 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
8563 hAccel = 0;
8565 trace("testing Alt press/release\n");
8566 flush_sequence();
8567 keybd_event(VK_MENU, 0, 0, 0);
8568 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8569 keybd_event(VK_MENU, 0, 0, 0);
8570 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8571 pump_msg_loop(hwnd, 0);
8572 /* this test doesn't pass in Wine for managed windows */
8573 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
8575 trace("testing VK_F1 press/release\n");
8576 keybd_event(VK_F1, 0, 0, 0);
8577 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
8578 pump_msg_loop(hwnd, 0);
8579 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
8581 trace("testing VK_APPS press/release\n");
8582 keybd_event(VK_APPS, 0, 0, 0);
8583 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
8584 pump_msg_loop(hwnd, 0);
8585 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
8587 trace("testing VK_F10 press/release\n");
8588 keybd_event(VK_F10, 0, 0, 0);
8589 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
8590 keybd_event(VK_F10, 0, 0, 0);
8591 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
8592 pump_msg_loop(hwnd, 0);
8593 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
8595 trace("testing SHIFT+F10 press/release\n");
8596 keybd_event(VK_SHIFT, 0, 0, 0);
8597 keybd_event(VK_F10, 0, 0, 0);
8598 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
8599 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8600 keybd_event(VK_ESCAPE, 0, 0, 0);
8601 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
8602 pump_msg_loop(hwnd, 0);
8603 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
8605 trace("testing Shift+MouseButton press/release\n");
8606 /* first, move mouse pointer inside of the window client area */
8607 GetClientRect(hwnd, &rc);
8608 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
8609 rc.left += (rc.right - rc.left)/2;
8610 rc.top += (rc.bottom - rc.top)/2;
8611 SetCursorPos(rc.left, rc.top);
8612 SetActiveWindow(hwnd);
8614 flush_events();
8615 flush_sequence();
8616 GetCursorPos(&pt);
8617 if (pt.x == rc.left && pt.y == rc.top)
8619 int i;
8620 keybd_event(VK_SHIFT, 0, 0, 0);
8621 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
8622 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8623 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8624 pump_msg_loop(hwnd, 0);
8625 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
8626 if (i < sequence_cnt)
8627 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
8628 else
8629 skip( "Shift+MouseButton event didn't get to the window\n" );
8632 done:
8633 if (hAccel) DestroyAcceleratorTable(hAccel);
8634 DestroyWindow(hwnd);
8637 /************* window procedures ********************/
8639 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
8640 WPARAM wParam, LPARAM lParam)
8642 static LONG defwndproc_counter = 0;
8643 static LONG beginpaint_counter = 0;
8644 LRESULT ret;
8645 struct recvd_message msg;
8647 if (ignore_message( message )) return 0;
8649 switch (message)
8651 case WM_ENABLE:
8653 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
8654 ok((BOOL)wParam == !(style & WS_DISABLED),
8655 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
8656 break;
8659 case WM_CAPTURECHANGED:
8660 if (test_DestroyWindow_flag)
8662 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
8663 if (style & WS_CHILD)
8664 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
8665 else if (style & WS_POPUP)
8666 lParam = WND_POPUP_ID;
8667 else
8668 lParam = WND_PARENT_ID;
8670 break;
8672 case WM_NCDESTROY:
8674 HWND capture;
8676 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
8677 capture = GetCapture();
8678 if (capture)
8680 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
8681 trace("current capture %p, releasing...\n", capture);
8682 ReleaseCapture();
8685 /* fall through */
8686 case WM_DESTROY:
8687 if (pGetAncestor)
8688 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
8689 if (test_DestroyWindow_flag)
8691 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
8692 if (style & WS_CHILD)
8693 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
8694 else if (style & WS_POPUP)
8695 lParam = WND_POPUP_ID;
8696 else
8697 lParam = WND_PARENT_ID;
8699 break;
8701 /* test_accelerators() depends on this */
8702 case WM_NCHITTEST:
8703 return HTCLIENT;
8705 case WM_USER+10:
8707 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
8708 HANDLE handle, event = (HANDLE)lParam;
8709 BOOL ret;
8711 handle = (void*)0xdeadbeef;
8712 ret = pGetCurrentActCtx(&handle);
8713 ok(ret, "failed to get current context, %u\n", GetLastError());
8714 ok(handle == 0, "got active context %p\n", handle);
8716 memset(&basicinfo, 0xff, sizeof(basicinfo));
8717 ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
8718 &basicinfo, sizeof(basicinfo), NULL);
8719 ok(ret, "got %d, error %d\n", ret, GetLastError());
8720 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
8721 ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
8723 if (event) SetEvent(event);
8724 return 1;
8727 /* ignore */
8728 case WM_MOUSEMOVE:
8729 case WM_MOUSEACTIVATE:
8730 case WM_NCMOUSEMOVE:
8731 case WM_SETCURSOR:
8732 case WM_IME_SELECT:
8733 return 0;
8736 msg.hwnd = hwnd;
8737 msg.message = message;
8738 msg.flags = sent|wparam|lparam;
8739 if (defwndproc_counter) msg.flags |= defwinproc;
8740 if (beginpaint_counter) msg.flags |= beginpaint;
8741 msg.wParam = wParam;
8742 msg.lParam = lParam;
8743 msg.descr = "MsgCheckProc";
8744 add_message(&msg);
8746 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
8748 HWND parent = GetParent(hwnd);
8749 RECT rc;
8750 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
8752 GetClientRect(parent, &rc);
8753 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
8754 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
8755 minmax->ptReserved.x, minmax->ptReserved.y,
8756 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
8757 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
8758 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
8759 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
8761 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
8762 minmax->ptMaxSize.x, rc.right);
8763 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
8764 minmax->ptMaxSize.y, rc.bottom);
8767 if (message == WM_PAINT)
8769 PAINTSTRUCT ps;
8770 beginpaint_counter++;
8771 BeginPaint( hwnd, &ps );
8772 beginpaint_counter--;
8773 EndPaint( hwnd, &ps );
8774 return 0;
8777 if (message == WM_CONTEXTMENU)
8779 /* don't create context menu */
8780 return 0;
8783 defwndproc_counter++;
8784 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
8785 : DefWindowProcA(hwnd, message, wParam, lParam);
8786 defwndproc_counter--;
8788 return ret;
8791 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8793 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
8796 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8798 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
8801 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8803 static LONG defwndproc_counter = 0;
8804 LRESULT ret;
8805 struct recvd_message msg;
8807 if (ignore_message( message )) return 0;
8809 switch (message)
8811 case WM_QUERYENDSESSION:
8812 case WM_ENDSESSION:
8813 lParam &= ~0x01; /* Vista adds a 0x01 flag */
8814 break;
8817 msg.hwnd = hwnd;
8818 msg.message = message;
8819 msg.flags = sent|wparam|lparam;
8820 if (defwndproc_counter) msg.flags |= defwinproc;
8821 msg.wParam = wParam;
8822 msg.lParam = lParam;
8823 msg.descr = "popup";
8824 add_message(&msg);
8826 if (message == WM_CREATE)
8828 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
8829 SetWindowLongA(hwnd, GWL_STYLE, style);
8832 defwndproc_counter++;
8833 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8834 defwndproc_counter--;
8836 return ret;
8839 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8841 static LONG defwndproc_counter = 0;
8842 static LONG beginpaint_counter = 0;
8843 LRESULT ret;
8844 struct recvd_message msg;
8846 if (ignore_message( message )) return 0;
8848 if (log_all_parent_messages ||
8849 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
8850 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
8851 message == WM_ENABLE || message == WM_ENTERIDLE ||
8852 message == WM_DRAWITEM || message == WM_COMMAND ||
8853 message == WM_IME_SETCONTEXT)
8855 switch (message)
8857 /* ignore */
8858 case WM_NCHITTEST:
8859 return HTCLIENT;
8860 case WM_SETCURSOR:
8861 case WM_MOUSEMOVE:
8862 case WM_NCMOUSEMOVE:
8863 return 0;
8865 case WM_ERASEBKGND:
8867 RECT rc;
8868 INT ret = GetClipBox((HDC)wParam, &rc);
8870 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
8871 break;
8875 msg.hwnd = hwnd;
8876 msg.message = message;
8877 msg.flags = sent|parent|wparam|lparam;
8878 if (defwndproc_counter) msg.flags |= defwinproc;
8879 if (beginpaint_counter) msg.flags |= beginpaint;
8880 msg.wParam = wParam;
8881 msg.lParam = lParam;
8882 msg.descr = "parent";
8883 add_message(&msg);
8886 if (message == WM_PAINT)
8888 PAINTSTRUCT ps;
8889 beginpaint_counter++;
8890 BeginPaint( hwnd, &ps );
8891 beginpaint_counter--;
8892 EndPaint( hwnd, &ps );
8893 return 0;
8896 defwndproc_counter++;
8897 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8898 defwndproc_counter--;
8900 return ret;
8903 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
8905 if (message == WM_CREATE)
8906 PostMessageA(hwnd, WM_CLOSE, 0, 0);
8907 else if (message == WM_CLOSE)
8909 /* Only the first WM_QUIT will survive the window destruction */
8910 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
8911 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
8912 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
8915 return DefWindowProcA(hwnd, message, wp, lp);
8918 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8920 static LONG defwndproc_counter = 0;
8921 LRESULT ret;
8922 struct recvd_message msg;
8924 if (ignore_message( message )) return 0;
8926 if (test_def_id)
8928 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
8929 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
8930 if (after_end_dialog)
8931 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
8932 else
8933 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
8936 msg.hwnd = hwnd;
8937 msg.message = message;
8938 msg.flags = sent|wparam|lparam;
8939 if (defwndproc_counter) msg.flags |= defwinproc;
8940 msg.wParam = wParam;
8941 msg.lParam = lParam;
8942 msg.descr = "dialog";
8943 add_message(&msg);
8945 defwndproc_counter++;
8946 ret = DefDlgProcA(hwnd, message, wParam, lParam);
8947 defwndproc_counter--;
8949 return ret;
8952 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8954 static LONG defwndproc_counter = 0;
8955 LRESULT ret;
8956 struct recvd_message msg;
8958 /* log only specific messages we are interested in */
8959 switch (message)
8961 #if 0 /* probably log these as well */
8962 case WM_ACTIVATE:
8963 case WM_SETFOCUS:
8964 case WM_KILLFOCUS:
8965 #endif
8966 case WM_SHOWWINDOW:
8967 case WM_SIZE:
8968 case WM_MOVE:
8969 case WM_GETMINMAXINFO:
8970 case WM_WINDOWPOSCHANGING:
8971 case WM_WINDOWPOSCHANGED:
8972 break;
8974 default: /* ignore */
8975 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
8976 return DefWindowProcA(hwnd, message, wParam, lParam);
8979 msg.hwnd = hwnd;
8980 msg.message = message;
8981 msg.flags = sent|wparam|lparam;
8982 if (defwndproc_counter) msg.flags |= defwinproc;
8983 msg.wParam = wParam;
8984 msg.lParam = lParam;
8985 msg.descr = "show";
8986 add_message(&msg);
8988 defwndproc_counter++;
8989 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8990 defwndproc_counter--;
8992 return ret;
8995 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
8997 switch (msg)
8999 case WM_CREATE: return 0;
9000 case WM_PAINT:
9002 MSG msg2;
9003 static int i = 0;
9005 if (i < 256)
9007 i++;
9008 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9010 TranslateMessage(&msg2);
9011 DispatchMessageA(&msg2);
9013 i--;
9015 else ok(broken(1), "infinite loop\n");
9016 if ( i == 0)
9017 paint_loop_done = TRUE;
9018 return DefWindowProcA(hWnd,msg,wParam,lParam);
9021 return DefWindowProcA(hWnd,msg,wParam,lParam);
9024 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9026 static LONG defwndproc_counter = 0;
9027 LRESULT ret;
9028 struct recvd_message msg;
9029 DWORD queue_status;
9031 if (ignore_message( message )) return 0;
9033 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9034 message == WM_HOTKEY || message >= WM_APP)
9036 msg.hwnd = hwnd;
9037 msg.message = message;
9038 msg.flags = sent|wparam|lparam;
9039 if (defwndproc_counter) msg.flags |= defwinproc;
9040 msg.wParam = wParam;
9041 msg.lParam = lParam;
9042 msg.descr = "HotkeyMsgCheckProcA";
9043 add_message(&msg);
9046 defwndproc_counter++;
9047 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9048 defwndproc_counter--;
9050 if (message == WM_APP)
9052 queue_status = GetQueueStatus(QS_HOTKEY);
9053 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9054 queue_status = GetQueueStatus(QS_POSTMESSAGE);
9055 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9056 PostMessageA(hwnd, WM_APP+1, 0, 0);
9058 else if (message == WM_APP+1)
9060 queue_status = GetQueueStatus(QS_HOTKEY);
9061 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9064 return ret;
9067 static BOOL RegisterWindowClasses(void)
9069 WNDCLASSA cls;
9070 WNDCLASSW clsW;
9072 cls.style = 0;
9073 cls.lpfnWndProc = MsgCheckProcA;
9074 cls.cbClsExtra = 0;
9075 cls.cbWndExtra = 0;
9076 cls.hInstance = GetModuleHandleA(0);
9077 cls.hIcon = 0;
9078 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9079 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9080 cls.lpszMenuName = NULL;
9081 cls.lpszClassName = "TestWindowClass";
9082 if(!RegisterClassA(&cls)) return FALSE;
9084 cls.lpfnWndProc = HotkeyMsgCheckProcA;
9085 cls.lpszClassName = "HotkeyWindowClass";
9086 if(!RegisterClassA(&cls)) return FALSE;
9088 cls.lpfnWndProc = ShowWindowProcA;
9089 cls.lpszClassName = "ShowWindowClass";
9090 if(!RegisterClassA(&cls)) return FALSE;
9092 cls.lpfnWndProc = PopupMsgCheckProcA;
9093 cls.lpszClassName = "TestPopupClass";
9094 if(!RegisterClassA(&cls)) return FALSE;
9096 cls.lpfnWndProc = ParentMsgCheckProcA;
9097 cls.lpszClassName = "TestParentClass";
9098 if(!RegisterClassA(&cls)) return FALSE;
9100 cls.lpfnWndProc = StopQuitMsgCheckProcA;
9101 cls.lpszClassName = "StopQuitClass";
9102 if(!RegisterClassA(&cls)) return FALSE;
9104 cls.lpfnWndProc = DefWindowProcA;
9105 cls.lpszClassName = "SimpleWindowClass";
9106 if(!RegisterClassA(&cls)) return FALSE;
9108 cls.lpfnWndProc = PaintLoopProcA;
9109 cls.lpszClassName = "PaintLoopWindowClass";
9110 if(!RegisterClassA(&cls)) return FALSE;
9112 cls.style = CS_NOCLOSE;
9113 cls.lpszClassName = "NoCloseWindowClass";
9114 if(!RegisterClassA(&cls)) return FALSE;
9116 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9117 cls.style = 0;
9118 cls.hInstance = GetModuleHandleA(0);
9119 cls.hbrBackground = 0;
9120 cls.lpfnWndProc = TestDlgProcA;
9121 cls.lpszClassName = "TestDialogClass";
9122 if(!RegisterClassA(&cls)) return FALSE;
9124 clsW.style = 0;
9125 clsW.lpfnWndProc = MsgCheckProcW;
9126 clsW.cbClsExtra = 0;
9127 clsW.cbWndExtra = 0;
9128 clsW.hInstance = GetModuleHandleW(0);
9129 clsW.hIcon = 0;
9130 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9131 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9132 clsW.lpszMenuName = NULL;
9133 clsW.lpszClassName = testWindowClassW;
9134 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
9136 return TRUE;
9139 static BOOL is_our_logged_class(HWND hwnd)
9141 char buf[256];
9143 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9145 if (!lstrcmpiA(buf, "TestWindowClass") ||
9146 !lstrcmpiA(buf, "ShowWindowClass") ||
9147 !lstrcmpiA(buf, "TestParentClass") ||
9148 !lstrcmpiA(buf, "TestPopupClass") ||
9149 !lstrcmpiA(buf, "SimpleWindowClass") ||
9150 !lstrcmpiA(buf, "TestDialogClass") ||
9151 !lstrcmpiA(buf, "MDI_frame_class") ||
9152 !lstrcmpiA(buf, "MDI_client_class") ||
9153 !lstrcmpiA(buf, "MDI_child_class") ||
9154 !lstrcmpiA(buf, "my_button_class") ||
9155 !lstrcmpiA(buf, "my_edit_class") ||
9156 !lstrcmpiA(buf, "static") ||
9157 !lstrcmpiA(buf, "ListBox") ||
9158 !lstrcmpiA(buf, "ComboBox") ||
9159 !lstrcmpiA(buf, "MyDialogClass") ||
9160 !lstrcmpiA(buf, "#32770") ||
9161 !lstrcmpiA(buf, "#32768"))
9162 return TRUE;
9164 return FALSE;
9167 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9169 HWND hwnd;
9171 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9173 if (nCode == HCBT_CLICKSKIPPED)
9175 /* ignore this event, XP sends it a lot when switching focus between windows */
9176 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9179 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9181 struct recvd_message msg;
9183 msg.hwnd = 0;
9184 msg.message = nCode;
9185 msg.flags = hook|wparam|lparam;
9186 msg.wParam = wParam;
9187 msg.lParam = lParam;
9188 msg.descr = "CBT";
9189 add_message(&msg);
9191 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9194 if (nCode == HCBT_DESTROYWND)
9196 if (test_DestroyWindow_flag)
9198 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9199 if (style & WS_CHILD)
9200 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9201 else if (style & WS_POPUP)
9202 lParam = WND_POPUP_ID;
9203 else
9204 lParam = WND_PARENT_ID;
9208 /* Log also SetFocus(0) calls */
9209 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9211 if (is_our_logged_class(hwnd))
9213 struct recvd_message msg;
9215 msg.hwnd = hwnd;
9216 msg.message = nCode;
9217 msg.flags = hook|wparam|lparam;
9218 msg.wParam = wParam;
9219 msg.lParam = lParam;
9220 msg.descr = "CBT";
9221 add_message(&msg);
9223 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9226 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
9227 DWORD event,
9228 HWND hwnd,
9229 LONG object_id,
9230 LONG child_id,
9231 DWORD thread_id,
9232 DWORD event_time)
9234 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9236 /* ignore mouse cursor events */
9237 if (object_id == OBJID_CURSOR) return;
9239 if (!hwnd || is_our_logged_class(hwnd))
9241 struct recvd_message msg;
9243 msg.hwnd = hwnd;
9244 msg.message = event;
9245 msg.flags = winevent_hook|wparam|lparam;
9246 msg.wParam = object_id;
9247 msg.lParam = child_id;
9248 msg.descr = "WEH";
9249 add_message(&msg);
9253 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
9254 static const WCHAR wszAnsi[] = {'U',0};
9256 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
9258 switch (uMsg)
9260 case CB_FINDSTRINGEXACT:
9261 trace("String: %p\n", (LPCWSTR)lParam);
9262 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
9263 return 1;
9264 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
9265 return 0;
9266 return -1;
9268 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
9271 static const struct message WmGetTextLengthAfromW[] = {
9272 { WM_GETTEXTLENGTH, sent },
9273 { WM_GETTEXT, sent|optional },
9274 { 0 }
9277 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
9279 /* dummy window proc for WM_GETTEXTLENGTH test */
9280 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
9282 switch(msg)
9284 case WM_GETTEXTLENGTH:
9285 return lstrlenW(dummy_window_text) + 37; /* some random length */
9286 case WM_GETTEXT:
9287 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
9288 return lstrlenW( (LPWSTR)lp );
9289 default:
9290 return DefWindowProcW( hwnd, msg, wp, lp );
9294 static void test_message_conversion(void)
9296 static const WCHAR wszMsgConversionClass[] =
9297 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
9298 WNDCLASSW cls;
9299 LRESULT lRes;
9300 HWND hwnd;
9301 WNDPROC wndproc, newproc;
9302 BOOL ret;
9304 cls.style = 0;
9305 cls.lpfnWndProc = MsgConversionProcW;
9306 cls.cbClsExtra = 0;
9307 cls.cbWndExtra = 0;
9308 cls.hInstance = GetModuleHandleW(NULL);
9309 cls.hIcon = NULL;
9310 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
9311 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
9312 cls.lpszMenuName = NULL;
9313 cls.lpszClassName = wszMsgConversionClass;
9314 /* this call will fail on Win9x, but that doesn't matter as this test is
9315 * meaningless on those platforms */
9316 if(!RegisterClassW(&cls)) return;
9318 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
9319 100, 100, 200, 200, 0, 0, 0, NULL);
9320 ok(hwnd != NULL, "Window creation failed\n");
9322 /* {W, A} -> A */
9324 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
9325 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9326 ok(lRes == 0, "String should have been converted\n");
9327 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9328 ok(lRes == 1, "String shouldn't have been converted\n");
9330 /* {W, A} -> W */
9332 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
9333 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9334 ok(lRes == 1, "String shouldn't have been converted\n");
9335 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9336 ok(lRes == 1, "String shouldn't have been converted\n");
9338 /* Synchronous messages */
9340 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9341 ok(lRes == 0, "String should have been converted\n");
9342 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9343 ok(lRes == 1, "String shouldn't have been converted\n");
9345 /* Asynchronous messages */
9347 SetLastError(0);
9348 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9349 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9350 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9351 SetLastError(0);
9352 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9353 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9354 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9355 SetLastError(0);
9356 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9357 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9358 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9359 SetLastError(0);
9360 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9361 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9362 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9363 SetLastError(0);
9364 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9365 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9366 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9367 SetLastError(0);
9368 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9369 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9370 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9371 SetLastError(0);
9372 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9373 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9374 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9375 SetLastError(0);
9376 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9377 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9378 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9380 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
9382 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
9383 WS_OVERLAPPEDWINDOW,
9384 100, 100, 200, 200, 0, 0, 0, NULL);
9385 assert(hwnd);
9386 flush_sequence();
9387 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
9388 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9389 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9390 "got bad length %ld\n", lRes );
9392 flush_sequence();
9393 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
9394 hwnd, WM_GETTEXTLENGTH, 0, 0);
9395 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9396 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9397 "got bad length %ld\n", lRes );
9399 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
9400 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
9401 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9402 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9403 NULL, 0, NULL, NULL ) ||
9404 broken(lRes == lstrlenW(dummy_window_text) + 37),
9405 "got bad length %ld\n", lRes );
9407 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
9408 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9409 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9410 NULL, 0, NULL, NULL ) ||
9411 broken(lRes == lstrlenW(dummy_window_text) + 37),
9412 "got bad length %ld\n", lRes );
9414 ret = DestroyWindow(hwnd);
9415 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9418 struct timer_info
9420 HWND hWnd;
9421 HANDLE handles[2];
9422 DWORD id;
9425 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
9429 #define TIMER_ID 0x19
9430 #define TIMER_COUNT_EXPECTED 100
9431 #define TIMER_COUNT_TOLERANCE 10
9433 static int count = 0;
9434 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9436 count++;
9439 static DWORD exception;
9440 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9442 count++;
9443 RaiseException(exception, 0, 0, NULL);
9446 static DWORD WINAPI timer_thread_proc(LPVOID x)
9448 struct timer_info *info = x;
9449 DWORD r;
9451 r = KillTimer(info->hWnd, 0x19);
9452 ok(r,"KillTimer failed in thread\n");
9453 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
9454 ok(r,"SetTimer failed in thread\n");
9455 ok(r==TIMER_ID,"SetTimer id different\n");
9456 r = SetEvent(info->handles[0]);
9457 ok(r,"SetEvent failed in thread\n");
9458 return 0;
9461 static void test_timers(void)
9463 struct timer_info info;
9464 DWORD start;
9465 DWORD id;
9466 MSG msg;
9468 info.hWnd = CreateWindowA("TestWindowClass", NULL,
9469 WS_OVERLAPPEDWINDOW ,
9470 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9471 NULL, NULL, 0);
9473 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
9474 ok(info.id, "SetTimer failed\n");
9475 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
9476 info.handles[0] = CreateEventW(NULL,0,0,NULL);
9477 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
9479 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
9481 WaitForSingleObject(info.handles[1], INFINITE);
9483 CloseHandle(info.handles[0]);
9484 CloseHandle(info.handles[1]);
9486 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
9488 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
9489 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
9490 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
9491 * ±9 counts (~4 ms) around the expected value.
9493 count = 0;
9494 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
9495 ok(id != 0, "did not get id from SetTimer.\n");
9496 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9497 start = GetTickCount();
9498 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9499 DispatchMessageA(&msg);
9500 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
9501 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
9502 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
9503 "did not get expected count for minimum timeout (%d != ~%d).\n",
9504 count, TIMER_COUNT_EXPECTED);
9505 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
9506 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
9507 if (pSetSystemTimer)
9509 int syscount = 0;
9511 count = 0;
9512 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
9513 ok(id != 0, "did not get id from SetSystemTimer.\n");
9514 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9515 start = GetTickCount();
9516 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9518 if (msg.message == WM_SYSTIMER)
9519 syscount++;
9520 DispatchMessageA(&msg);
9522 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
9523 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
9524 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
9525 "did not get expected count for minimum timeout (%d != ~%d).\n",
9526 syscount, TIMER_COUNT_EXPECTED);
9527 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
9528 count);
9529 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
9532 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
9535 static void test_timers_no_wnd(void)
9537 static UINT_PTR ids[0xffff];
9538 UINT_PTR id, id2;
9539 DWORD start;
9540 MSG msg;
9541 int i;
9543 count = 0;
9544 id = SetTimer(NULL, 0, 100, callback_count);
9545 ok(id != 0, "did not get id from SetTimer.\n");
9546 id2 = SetTimer(NULL, id, 200, callback_count);
9547 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
9548 Sleep(150);
9549 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9550 ok(count == 0, "did not get zero count as expected (%i).\n", count);
9551 Sleep(150);
9552 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9553 ok(count == 1, "did not get one count as expected (%i).\n", count);
9554 KillTimer(NULL, id);
9555 Sleep(250);
9556 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9557 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
9559 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
9560 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
9561 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
9562 * ±9 counts (~4 ms) around the expected value.
9564 count = 0;
9565 id = SetTimer(NULL, 0, 0, callback_count);
9566 ok(id != 0, "did not get id from SetTimer.\n");
9567 start = GetTickCount();
9568 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
9569 DispatchMessageA(&msg);
9570 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
9571 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
9572 "did not get expected count for minimum timeout (%d != ~%d).\n",
9573 count, TIMER_COUNT_EXPECTED);
9574 KillTimer(NULL, id);
9575 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
9577 if (pSetCoalescableTimer)
9579 count = 0;
9580 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
9581 ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
9582 start = GetTickCount();
9583 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
9584 DispatchMessageA(&msg);
9585 ok(count > 1, "expected count > 1, got %d.\n", count);
9586 KillTimer(NULL, id);
9588 else
9589 win_skip("SetCoalescableTimer not available.\n");
9591 /* Check what happens when we're running out of timers */
9592 for (i=0; i<sizeof(ids)/sizeof(ids[0]); i++)
9594 SetLastError(0xdeadbeef);
9595 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
9596 if (!ids[i]) break;
9598 ok(i != sizeof(ids)/sizeof(ids[0]), "all timers were created successfully\n");
9599 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
9600 "GetLastError() = %d\n", GetLastError());
9601 while (i > 0) KillTimer(NULL, ids[--i]);
9604 static void test_timers_exception(DWORD code)
9606 UINT_PTR id;
9607 MSG msg;
9609 exception = code;
9610 id = SetTimer(NULL, 0, 1000, callback_exception);
9611 ok(id != 0, "did not get id from SetTimer.\n");
9613 memset(&msg, 0, sizeof(msg));
9614 msg.message = WM_TIMER;
9615 msg.wParam = id;
9616 msg.lParam = (LPARAM)callback_exception;
9618 count = 0;
9619 DispatchMessageA(&msg);
9620 ok(count == 1, "did not get one count as expected (%i).\n", count);
9622 KillTimer(NULL, id);
9625 static void test_timers_exceptions(void)
9627 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
9628 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
9629 test_timers_exception(EXCEPTION_BREAKPOINT);
9630 test_timers_exception(EXCEPTION_SINGLE_STEP);
9631 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
9632 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
9633 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
9634 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
9635 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
9636 test_timers_exception(0xE000BEEF); /* customer exception */
9639 /* Various win events with arbitrary parameters */
9640 static const struct message WmWinEventsSeq[] = {
9641 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
9642 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9643 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
9644 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
9645 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
9646 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
9647 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
9648 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
9649 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
9650 /* our win event hook ignores OBJID_CURSOR events */
9651 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
9652 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
9653 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
9654 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
9655 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
9656 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
9657 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9658 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
9659 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
9660 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
9661 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
9662 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
9663 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
9664 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
9665 { 0 }
9667 static const struct message WmWinEventCaretSeq[] = {
9668 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
9669 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
9670 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
9671 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
9672 { 0 }
9674 static const struct message WmWinEventCaretSeq_2[] = {
9675 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
9676 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
9677 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
9678 { 0 }
9680 static const struct message WmWinEventAlertSeq[] = {
9681 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
9682 { 0 }
9684 static const struct message WmWinEventAlertSeq_2[] = {
9685 /* create window in the thread proc */
9686 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
9687 /* our test event */
9688 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
9689 { 0 }
9691 static const struct message WmGlobalHookSeq_1[] = {
9692 /* create window in the thread proc */
9693 { HCBT_CREATEWND, hook|lparam, 0, 2 },
9694 /* our test events */
9695 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
9696 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
9697 { 0 }
9699 static const struct message WmGlobalHookSeq_2[] = {
9700 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
9701 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
9702 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
9703 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
9704 { 0 }
9707 static const struct message WmMouseLLHookSeq[] = {
9708 { WM_MOUSEMOVE, hook },
9709 { WM_LBUTTONUP, hook },
9710 { WM_MOUSEMOVE, hook },
9711 { 0 }
9714 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
9715 DWORD event,
9716 HWND hwnd,
9717 LONG object_id,
9718 LONG child_id,
9719 DWORD thread_id,
9720 DWORD event_time)
9722 char buf[256];
9724 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9726 if (!lstrcmpiA(buf, "TestWindowClass") ||
9727 !lstrcmpiA(buf, "static"))
9729 struct recvd_message msg;
9731 msg.hwnd = hwnd;
9732 msg.message = event;
9733 msg.flags = winevent_hook|wparam|lparam;
9734 msg.wParam = object_id;
9735 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
9736 msg.descr = "WEH_2";
9737 add_message(&msg);
9742 static HHOOK hCBT_global_hook;
9743 static DWORD cbt_global_hook_thread_id;
9745 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9747 HWND hwnd;
9748 char buf[256];
9750 if (nCode == HCBT_SYSCOMMAND)
9752 struct recvd_message msg;
9754 msg.hwnd = 0;
9755 msg.message = nCode;
9756 msg.flags = hook|wparam|lparam;
9757 msg.wParam = wParam;
9758 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
9759 msg.descr = "CBT_2";
9760 add_message(&msg);
9762 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
9764 /* WH_MOUSE_LL hook */
9765 if (nCode == HC_ACTION)
9767 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
9769 /* we can't test for real mouse events */
9770 if (mhll->flags & LLMHF_INJECTED)
9772 struct recvd_message msg;
9774 memset (&msg, 0, sizeof (msg));
9775 msg.message = wParam;
9776 msg.flags = hook;
9777 msg.descr = "CBT_2";
9778 add_message(&msg);
9780 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
9783 /* Log also SetFocus(0) calls */
9784 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9786 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9788 if (!lstrcmpiA(buf, "TestWindowClass") ||
9789 !lstrcmpiA(buf, "static"))
9791 struct recvd_message msg;
9793 msg.hwnd = hwnd;
9794 msg.message = nCode;
9795 msg.flags = hook|wparam|lparam;
9796 msg.wParam = wParam;
9797 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
9798 msg.descr = "CBT_2";
9799 add_message(&msg);
9802 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
9805 static DWORD WINAPI win_event_global_thread_proc(void *param)
9807 HWND hwnd;
9808 MSG msg;
9809 HANDLE hevent = *(HANDLE *)param;
9811 assert(pNotifyWinEvent);
9813 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
9814 assert(hwnd);
9815 trace("created thread window %p\n", hwnd);
9817 *(HWND *)param = hwnd;
9819 flush_sequence();
9820 /* this event should be received only by our new hook proc,
9821 * an old one does not expect an event from another thread.
9823 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
9824 SetEvent(hevent);
9826 while (GetMessageA(&msg, 0, 0, 0))
9828 TranslateMessage(&msg);
9829 DispatchMessageA(&msg);
9831 return 0;
9834 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
9836 HWND hwnd;
9837 MSG msg;
9838 HANDLE hevent = *(HANDLE *)param;
9840 flush_sequence();
9841 /* these events should be received only by our new hook proc,
9842 * an old one does not expect an event from another thread.
9845 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
9846 assert(hwnd);
9847 trace("created thread window %p\n", hwnd);
9849 *(HWND *)param = hwnd;
9851 /* Windows doesn't like when a thread plays games with the focus,
9852 that leads to all kinds of misbehaviours and failures to activate
9853 a window. So, better keep next lines commented out.
9854 SetFocus(0);
9855 SetFocus(hwnd);*/
9857 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
9858 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
9860 SetEvent(hevent);
9862 while (GetMessageA(&msg, 0, 0, 0))
9864 TranslateMessage(&msg);
9865 DispatchMessageA(&msg);
9867 return 0;
9870 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
9872 HWND hwnd;
9873 MSG msg;
9874 HANDLE hevent = *(HANDLE *)param;
9876 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
9877 assert(hwnd);
9878 trace("created thread window %p\n", hwnd);
9880 *(HWND *)param = hwnd;
9882 flush_sequence();
9884 /* Windows doesn't like when a thread plays games with the focus,
9885 * that leads to all kinds of misbehaviours and failures to activate
9886 * a window. So, better don't generate a mouse click message below.
9888 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9889 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9890 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9892 SetEvent(hevent);
9893 while (GetMessageA(&msg, 0, 0, 0))
9895 TranslateMessage(&msg);
9896 DispatchMessageA(&msg);
9898 return 0;
9901 static void test_winevents(void)
9903 BOOL ret;
9904 MSG msg;
9905 HWND hwnd, hwnd2;
9906 UINT i;
9907 HANDLE hthread, hevent;
9908 DWORD tid;
9909 HWINEVENTHOOK hhook;
9910 const struct message *events = WmWinEventsSeq;
9912 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
9913 WS_OVERLAPPEDWINDOW,
9914 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9915 NULL, NULL, 0);
9916 assert(hwnd);
9918 /****** start of global hook test *************/
9919 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
9920 if (!hCBT_global_hook)
9922 ok(DestroyWindow(hwnd), "failed to destroy window\n");
9923 skip( "cannot set global hook\n" );
9924 return;
9927 hevent = CreateEventA(NULL, 0, 0, NULL);
9928 assert(hevent);
9929 hwnd2 = hevent;
9931 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
9932 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
9934 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9936 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
9938 flush_sequence();
9939 /* this one should be received only by old hook proc */
9940 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
9941 /* this one should be received only by old hook proc */
9942 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
9944 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
9946 ret = UnhookWindowsHookEx(hCBT_global_hook);
9947 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
9949 PostThreadMessageA(tid, WM_QUIT, 0, 0);
9950 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9951 CloseHandle(hthread);
9952 CloseHandle(hevent);
9953 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
9954 /****** end of global hook test *************/
9956 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
9958 ok(DestroyWindow(hwnd), "failed to destroy window\n");
9959 return;
9962 flush_sequence();
9964 if (0)
9966 /* this test doesn't pass under Win9x */
9967 /* win2k ignores events with hwnd == 0 */
9968 SetLastError(0xdeadbeef);
9969 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
9970 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
9971 GetLastError() == 0xdeadbeef, /* Win9x */
9972 "unexpected error %d\n", GetLastError());
9973 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
9976 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
9977 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
9979 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
9981 /****** start of event filtering test *************/
9982 hhook = pSetWinEventHook(
9983 EVENT_OBJECT_SHOW, /* 0x8002 */
9984 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
9985 GetModuleHandleA(0), win_event_global_hook_proc,
9986 GetCurrentProcessId(), 0,
9987 WINEVENT_INCONTEXT);
9988 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
9990 hevent = CreateEventA(NULL, 0, 0, NULL);
9991 assert(hevent);
9992 hwnd2 = hevent;
9994 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
9995 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
9997 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9999 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10001 flush_sequence();
10002 /* this one should be received only by old hook proc */
10003 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10004 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10005 /* this one should be received only by old hook proc */
10006 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10008 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10010 ret = pUnhookWinEvent(hhook);
10011 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10013 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10014 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10015 CloseHandle(hthread);
10016 CloseHandle(hevent);
10017 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10018 /****** end of event filtering test *************/
10020 /****** start of out of context event test *************/
10021 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10022 win_event_global_hook_proc, GetCurrentProcessId(), 0,
10023 WINEVENT_OUTOFCONTEXT);
10024 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10026 hevent = CreateEventA(NULL, 0, 0, NULL);
10027 assert(hevent);
10028 hwnd2 = hevent;
10030 flush_sequence();
10032 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10033 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10035 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10037 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10038 /* process pending winevent messages */
10039 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10040 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10042 flush_sequence();
10043 /* this one should be received only by old hook proc */
10044 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10045 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10046 /* this one should be received only by old hook proc */
10047 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10049 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10050 /* process pending winevent messages */
10051 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10052 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10054 ret = pUnhookWinEvent(hhook);
10055 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10057 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10058 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10059 CloseHandle(hthread);
10060 CloseHandle(hevent);
10061 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10062 /****** end of out of context event test *************/
10064 /****** start of MOUSE_LL hook test *************/
10065 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10066 /* WH_MOUSE_LL is not supported on Win9x platforms */
10067 if (!hCBT_global_hook)
10069 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10070 goto skip_mouse_ll_hook_test;
10073 hevent = CreateEventA(NULL, 0, 0, NULL);
10074 assert(hevent);
10075 hwnd2 = hevent;
10077 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10078 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10080 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10081 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10083 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10084 flush_sequence();
10086 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10087 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10088 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10090 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10092 ret = UnhookWindowsHookEx(hCBT_global_hook);
10093 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10095 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10096 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10097 CloseHandle(hthread);
10098 CloseHandle(hevent);
10099 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10100 /****** end of MOUSE_LL hook test *************/
10101 skip_mouse_ll_hook_test:
10103 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10106 static void test_set_hook(void)
10108 BOOL ret;
10109 HHOOK hhook;
10110 HWINEVENTHOOK hwinevent_hook;
10112 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10113 ok(hhook != 0, "local hook does not require hModule set to 0\n");
10114 UnhookWindowsHookEx(hhook);
10116 if (0)
10118 /* this test doesn't pass under Win9x: BUG! */
10119 SetLastError(0xdeadbeef);
10120 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10121 ok(!hhook, "global hook requires hModule != 0\n");
10122 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10125 SetLastError(0xdeadbeef);
10126 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10127 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10128 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10129 GetLastError() == 0xdeadbeef, /* Win9x */
10130 "unexpected error %d\n", GetLastError());
10132 SetLastError(0xdeadbeef);
10133 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10134 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10135 GetLastError() == 0xdeadbeef, /* Win9x */
10136 "unexpected error %d\n", GetLastError());
10138 if (!pSetWinEventHook || !pUnhookWinEvent) return;
10140 /* even process local incontext hooks require hmodule */
10141 SetLastError(0xdeadbeef);
10142 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10143 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10144 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10145 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10146 GetLastError() == 0xdeadbeef, /* Win9x */
10147 "unexpected error %d\n", GetLastError());
10149 /* even thread local incontext hooks require hmodule */
10150 SetLastError(0xdeadbeef);
10151 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10152 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10153 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10154 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10155 GetLastError() == 0xdeadbeef, /* Win9x */
10156 "unexpected error %d\n", GetLastError());
10158 if (0)
10160 /* these 3 tests don't pass under Win9x */
10161 SetLastError(0xdeadbeef);
10162 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10163 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10164 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10165 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10167 SetLastError(0xdeadbeef);
10168 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10169 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10170 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10171 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10173 SetLastError(0xdeadbeef);
10174 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10175 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10176 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10177 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10180 SetLastError(0xdeadbeef);
10181 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10182 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10183 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10184 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10185 ret = pUnhookWinEvent(hwinevent_hook);
10186 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10188 todo_wine {
10189 /* This call succeeds under win2k SP4, but fails under Wine.
10190 Does win2k test/use passed process id? */
10191 SetLastError(0xdeadbeef);
10192 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10193 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10194 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10195 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10196 ret = pUnhookWinEvent(hwinevent_hook);
10197 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10200 SetLastError(0xdeadbeef);
10201 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10202 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10203 GetLastError() == 0xdeadbeef, /* Win9x */
10204 "unexpected error %d\n", GetLastError());
10207 static HWND hook_hwnd;
10208 static HHOOK recursive_hook;
10209 static int hook_depth, max_hook_depth;
10211 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
10213 LRESULT res;
10214 MSG msg;
10215 BOOL b;
10217 hook_depth++;
10218 if(hook_depth > max_hook_depth)
10219 max_hook_depth = hook_depth;
10221 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
10222 ok(b, "PeekMessage failed\n");
10224 res = CallNextHookEx(recursive_hook, code, w, l);
10226 hook_depth--;
10227 return res;
10230 static void test_recursive_hook(void)
10232 MSG msg;
10233 BOOL b;
10235 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
10236 ok(hook_hwnd != NULL, "CreateWindow failed\n");
10238 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
10239 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
10241 PostMessageW(hook_hwnd, WM_USER, 0, 0);
10242 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
10244 hook_depth = 0;
10245 GetMessageW(&msg, hook_hwnd, 0, 0);
10246 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
10247 trace("max_hook_depth = %d\n", max_hook_depth);
10249 b = UnhookWindowsHookEx(recursive_hook);
10250 ok(b, "UnhokWindowsHookEx failed\n");
10252 DestroyWindow(hook_hwnd);
10255 static const struct message ScrollWindowPaint1[] = {
10256 { WM_PAINT, sent },
10257 { WM_ERASEBKGND, sent|beginpaint },
10258 { WM_GETTEXTLENGTH, sent|optional },
10259 { WM_PAINT, sent|optional },
10260 { WM_NCPAINT, sent|beginpaint|optional },
10261 { WM_GETTEXT, sent|beginpaint|optional },
10262 { WM_GETTEXT, sent|beginpaint|optional },
10263 { WM_GETTEXT, sent|beginpaint|optional },
10264 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
10265 { WM_ERASEBKGND, sent|beginpaint|optional },
10266 { 0 }
10269 static const struct message ScrollWindowPaint2[] = {
10270 { WM_PAINT, sent },
10271 { 0 }
10274 static void test_scrollwindowex(void)
10276 HWND hwnd, hchild;
10277 RECT rect={0,0,130,130};
10279 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
10280 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
10281 100, 100, 200, 200, 0, 0, 0, NULL);
10282 ok (hwnd != 0, "Failed to create overlapped window\n");
10283 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
10284 WS_VISIBLE|WS_CAPTION|WS_CHILD,
10285 10, 10, 150, 150, hwnd, 0, 0, NULL);
10286 ok (hchild != 0, "Failed to create child\n");
10287 UpdateWindow(hwnd);
10288 flush_events();
10289 flush_sequence();
10291 /* scroll without the child window */
10292 trace("start scroll\n");
10293 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10294 SW_ERASE|SW_INVALIDATE);
10295 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10296 trace("end scroll\n");
10297 flush_sequence();
10298 flush_events();
10299 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10300 flush_events();
10301 flush_sequence();
10303 /* Now without the SW_ERASE flag */
10304 trace("start scroll\n");
10305 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
10306 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10307 trace("end scroll\n");
10308 flush_sequence();
10309 flush_events();
10310 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
10311 flush_events();
10312 flush_sequence();
10314 /* now scroll the child window as well */
10315 trace("start scroll\n");
10316 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10317 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
10318 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
10319 /* windows sometimes a WM_MOVE */
10320 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
10321 trace("end scroll\n");
10322 flush_sequence();
10323 flush_events();
10324 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10325 flush_events();
10326 flush_sequence();
10328 /* now scroll with ScrollWindow() */
10329 trace("start scroll with ScrollWindow\n");
10330 ScrollWindow( hwnd, 5, 5, NULL, NULL);
10331 trace("end scroll\n");
10332 flush_sequence();
10333 flush_events();
10334 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
10336 ok(DestroyWindow(hchild), "failed to destroy window\n");
10337 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10338 flush_sequence();
10341 static const struct message destroy_window_with_children[] = {
10342 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10343 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
10344 { 0x0090, sent|optional },
10345 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
10346 { 0x0090, sent|optional },
10347 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10348 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10349 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10350 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10351 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
10352 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10353 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10354 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10355 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10356 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10357 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10358 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10359 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10360 { 0 }
10363 static void test_DestroyWindow(void)
10365 BOOL ret;
10366 HWND parent, child1, child2, child3, child4, test;
10367 UINT_PTR child_id = WND_CHILD_ID + 1;
10369 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10370 100, 100, 200, 200, 0, 0, 0, NULL);
10371 assert(parent != 0);
10372 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10373 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
10374 assert(child1 != 0);
10375 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10376 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
10377 assert(child2 != 0);
10378 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10379 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
10380 assert(child3 != 0);
10381 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
10382 0, 0, 50, 50, parent, 0, 0, NULL);
10383 assert(child4 != 0);
10385 /* test owner/parent of child2 */
10386 test = GetParent(child2);
10387 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10388 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10389 if(pGetAncestor) {
10390 test = pGetAncestor(child2, GA_PARENT);
10391 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10393 test = GetWindow(child2, GW_OWNER);
10394 ok(!test, "wrong owner %p\n", test);
10396 test = SetParent(child2, parent);
10397 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
10399 /* test owner/parent of the parent */
10400 test = GetParent(parent);
10401 ok(!test, "wrong parent %p\n", test);
10402 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
10403 if(pGetAncestor) {
10404 test = pGetAncestor(parent, GA_PARENT);
10405 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10407 test = GetWindow(parent, GW_OWNER);
10408 ok(!test, "wrong owner %p\n", test);
10410 /* test owner/parent of child1 */
10411 test = GetParent(child1);
10412 ok(test == parent, "wrong parent %p\n", test);
10413 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
10414 if(pGetAncestor) {
10415 test = pGetAncestor(child1, GA_PARENT);
10416 ok(test == parent, "wrong parent %p\n", test);
10418 test = GetWindow(child1, GW_OWNER);
10419 ok(!test, "wrong owner %p\n", test);
10421 /* test owner/parent of child2 */
10422 test = GetParent(child2);
10423 ok(test == parent, "wrong parent %p\n", test);
10424 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10425 if(pGetAncestor) {
10426 test = pGetAncestor(child2, GA_PARENT);
10427 ok(test == parent, "wrong parent %p\n", test);
10429 test = GetWindow(child2, GW_OWNER);
10430 ok(!test, "wrong owner %p\n", test);
10432 /* test owner/parent of child3 */
10433 test = GetParent(child3);
10434 ok(test == child1, "wrong parent %p\n", test);
10435 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
10436 if(pGetAncestor) {
10437 test = pGetAncestor(child3, GA_PARENT);
10438 ok(test == child1, "wrong parent %p\n", test);
10440 test = GetWindow(child3, GW_OWNER);
10441 ok(!test, "wrong owner %p\n", test);
10443 /* test owner/parent of child4 */
10444 test = GetParent(child4);
10445 ok(test == parent, "wrong parent %p\n", test);
10446 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
10447 if(pGetAncestor) {
10448 test = pGetAncestor(child4, GA_PARENT);
10449 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10451 test = GetWindow(child4, GW_OWNER);
10452 ok(test == parent, "wrong owner %p\n", test);
10454 flush_sequence();
10456 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
10457 parent, child1, child2, child3, child4);
10459 SetCapture(child4);
10460 test = GetCapture();
10461 ok(test == child4, "wrong capture window %p\n", test);
10463 test_DestroyWindow_flag = TRUE;
10464 ret = DestroyWindow(parent);
10465 ok( ret, "DestroyWindow() error %d\n", GetLastError());
10466 test_DestroyWindow_flag = FALSE;
10467 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
10469 ok(!IsWindow(parent), "parent still exists\n");
10470 ok(!IsWindow(child1), "child1 still exists\n");
10471 ok(!IsWindow(child2), "child2 still exists\n");
10472 ok(!IsWindow(child3), "child3 still exists\n");
10473 ok(!IsWindow(child4), "child4 still exists\n");
10475 test = GetCapture();
10476 ok(!test, "wrong capture window %p\n", test);
10480 static const struct message WmDispatchPaint[] = {
10481 { WM_NCPAINT, sent },
10482 { WM_GETTEXT, sent|defwinproc|optional },
10483 { WM_GETTEXT, sent|defwinproc|optional },
10484 { WM_ERASEBKGND, sent },
10485 { 0 }
10488 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10490 if (message == WM_PAINT) return 0;
10491 return MsgCheckProcA( hwnd, message, wParam, lParam );
10494 static void test_DispatchMessage(void)
10496 RECT rect;
10497 MSG msg;
10498 int count;
10499 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10500 100, 100, 200, 200, 0, 0, 0, NULL);
10501 ShowWindow( hwnd, SW_SHOW );
10502 UpdateWindow( hwnd );
10503 flush_events();
10504 flush_sequence();
10505 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
10507 SetRect( &rect, -5, -5, 5, 5 );
10508 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10509 count = 0;
10510 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10512 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10513 else
10515 flush_sequence();
10516 DispatchMessageA( &msg );
10517 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
10518 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10519 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
10520 if (++count > 10) break;
10523 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
10525 trace("now without DispatchMessage\n");
10526 flush_sequence();
10527 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10528 count = 0;
10529 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10531 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10532 else
10534 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
10535 flush_sequence();
10536 /* this will send WM_NCCPAINT just like DispatchMessage does */
10537 GetUpdateRgn( hwnd, hrgn, TRUE );
10538 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10539 DeleteObject( hrgn );
10540 GetClientRect( hwnd, &rect );
10541 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
10542 ok( !count, "Got multiple WM_PAINTs\n" );
10543 if (++count > 10) break;
10547 flush_sequence();
10548 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10549 count = 0;
10550 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10552 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10553 else
10555 HDC hdc;
10557 flush_sequence();
10558 hdc = BeginPaint( hwnd, NULL );
10559 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
10560 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
10561 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10562 ok( !count, "Got multiple WM_PAINTs\n" );
10563 if (++count > 10) break;
10566 DestroyWindow(hwnd);
10570 static const struct message WmUser[] = {
10571 { WM_USER, sent },
10572 { 0 }
10575 struct sendmsg_info
10577 HWND hwnd;
10578 DWORD timeout;
10579 DWORD ret;
10582 static DWORD CALLBACK send_msg_thread( LPVOID arg )
10584 struct sendmsg_info *info = arg;
10585 SetLastError( 0xdeadbeef );
10586 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
10587 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
10588 broken(GetLastError() == 0), /* win9x */
10589 "unexpected error %d\n", GetLastError());
10590 return 0;
10593 static void wait_for_thread( HANDLE thread )
10595 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
10597 MSG msg;
10598 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
10602 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10604 if (message == WM_USER) Sleep(200);
10605 return MsgCheckProcA( hwnd, message, wParam, lParam );
10608 static void test_SendMessageTimeout(void)
10610 HANDLE thread;
10611 struct sendmsg_info info;
10612 DWORD tid;
10613 BOOL is_win9x;
10615 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10616 100, 100, 200, 200, 0, 0, 0, NULL);
10617 flush_events();
10618 flush_sequence();
10620 info.timeout = 1000;
10621 info.ret = 0xdeadbeef;
10622 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10623 wait_for_thread( thread );
10624 CloseHandle( thread );
10625 ok( info.ret == 1, "SendMessageTimeout failed\n" );
10626 ok_sequence( WmUser, "WmUser", FALSE );
10628 info.timeout = 1;
10629 info.ret = 0xdeadbeef;
10630 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10631 Sleep(100); /* SendMessageTimeout should time out here */
10632 wait_for_thread( thread );
10633 CloseHandle( thread );
10634 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
10635 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
10637 /* 0 means infinite timeout (but not on win9x) */
10638 info.timeout = 0;
10639 info.ret = 0xdeadbeef;
10640 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10641 Sleep(100);
10642 wait_for_thread( thread );
10643 CloseHandle( thread );
10644 is_win9x = !info.ret;
10645 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
10646 else ok_sequence( WmUser, "WmUser", FALSE );
10648 /* timeout is treated as signed despite the prototype (but not on win9x) */
10649 info.timeout = 0x7fffffff;
10650 info.ret = 0xdeadbeef;
10651 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10652 Sleep(100);
10653 wait_for_thread( thread );
10654 CloseHandle( thread );
10655 ok( info.ret == 1, "SendMessageTimeout failed\n" );
10656 ok_sequence( WmUser, "WmUser", FALSE );
10658 info.timeout = 0x80000000;
10659 info.ret = 0xdeadbeef;
10660 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10661 Sleep(100);
10662 wait_for_thread( thread );
10663 CloseHandle( thread );
10664 if (is_win9x)
10666 ok( info.ret == 1, "SendMessageTimeout failed\n" );
10667 ok_sequence( WmUser, "WmUser", FALSE );
10669 else
10671 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
10672 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
10675 /* now check for timeout during message processing */
10676 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
10677 info.timeout = 100;
10678 info.ret = 0xdeadbeef;
10679 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10680 wait_for_thread( thread );
10681 CloseHandle( thread );
10682 /* we should time out but still get the message */
10683 ok( info.ret == 0, "SendMessageTimeout failed\n" );
10684 ok_sequence( WmUser, "WmUser", FALSE );
10686 DestroyWindow( info.hwnd );
10690 /****************** edit message test *************************/
10691 #define ID_EDIT 0x1234
10692 static const struct message sl_edit_setfocus[] =
10694 { HCBT_SETFOCUS, hook },
10695 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10696 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10697 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10698 { WM_SETFOCUS, sent|wparam, 0 },
10699 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10700 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
10701 { WM_CTLCOLOREDIT, sent|parent },
10702 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10703 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10704 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10705 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10706 { 0 }
10708 static const struct message sl_edit_invisible[] =
10710 { HCBT_SETFOCUS, hook },
10711 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10712 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10713 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10714 { WM_KILLFOCUS, sent|parent },
10715 { WM_SETFOCUS, sent },
10716 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10717 { 0 }
10719 static const struct message ml_edit_setfocus[] =
10721 { HCBT_SETFOCUS, hook },
10722 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10723 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10724 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10725 { WM_SETFOCUS, sent|wparam, 0 },
10726 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10727 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10728 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10729 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10730 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10731 { 0 }
10733 static const struct message sl_edit_killfocus[] =
10735 { HCBT_SETFOCUS, hook },
10736 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10737 { WM_KILLFOCUS, sent|wparam, 0 },
10738 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10739 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10740 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
10741 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10742 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10743 { 0 }
10745 static const struct message sl_edit_lbutton_dblclk[] =
10747 { WM_LBUTTONDBLCLK, sent },
10748 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10749 { 0 }
10751 static const struct message sl_edit_lbutton_down[] =
10753 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
10754 { HCBT_SETFOCUS, hook },
10755 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10756 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10757 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10758 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
10759 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10760 { WM_CTLCOLOREDIT, sent|parent },
10761 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10762 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10763 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10764 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10765 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10766 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10767 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10768 { WM_CTLCOLOREDIT, sent|parent|optional },
10769 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10770 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10771 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10772 { 0 }
10774 static const struct message ml_edit_lbutton_down[] =
10776 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
10777 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10778 { HCBT_SETFOCUS, hook },
10779 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10780 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10781 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10782 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
10783 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10784 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10785 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10786 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10787 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10788 { 0 }
10790 static const struct message sl_edit_lbutton_up[] =
10792 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10793 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10794 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10795 { WM_CAPTURECHANGED, sent|defwinproc },
10796 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10797 { 0 }
10799 static const struct message ml_edit_lbutton_up[] =
10801 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10802 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10803 { WM_CAPTURECHANGED, sent|defwinproc },
10804 { 0 }
10807 static WNDPROC old_edit_proc;
10809 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10811 static LONG defwndproc_counter = 0;
10812 LRESULT ret;
10813 struct recvd_message msg;
10815 if (ignore_message( message )) return 0;
10817 msg.hwnd = hwnd;
10818 msg.message = message;
10819 msg.flags = sent|wparam|lparam;
10820 if (defwndproc_counter) msg.flags |= defwinproc;
10821 msg.wParam = wParam;
10822 msg.lParam = lParam;
10823 msg.descr = "edit";
10824 add_message(&msg);
10826 defwndproc_counter++;
10827 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
10828 defwndproc_counter--;
10830 return ret;
10833 static void subclass_edit(void)
10835 WNDCLASSA cls;
10837 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
10839 old_edit_proc = cls.lpfnWndProc;
10841 cls.hInstance = GetModuleHandleA(NULL);
10842 cls.lpfnWndProc = edit_hook_proc;
10843 cls.lpszClassName = "my_edit_class";
10844 UnregisterClassA(cls.lpszClassName, cls.hInstance);
10845 if (!RegisterClassA(&cls)) assert(0);
10848 static void test_edit_messages(void)
10850 HWND hwnd, parent;
10851 DWORD dlg_code;
10853 subclass_edit();
10854 log_all_parent_messages++;
10856 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10857 100, 100, 200, 200, 0, 0, 0, NULL);
10858 ok (parent != 0, "Failed to create parent window\n");
10860 /* test single line edit */
10861 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
10862 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
10863 ok(hwnd != 0, "Failed to create edit window\n");
10865 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
10866 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
10868 flush_sequence();
10869 SetFocus(hwnd);
10870 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
10872 ShowWindow(hwnd, SW_SHOW);
10873 UpdateWindow(hwnd);
10874 SetFocus(0);
10875 flush_sequence();
10877 SetFocus(hwnd);
10878 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
10880 SetFocus(0);
10881 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
10883 SetFocus(0);
10884 ReleaseCapture();
10885 flush_sequence();
10887 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
10888 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
10890 SetFocus(0);
10891 ReleaseCapture();
10892 flush_sequence();
10894 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
10895 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
10897 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
10898 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
10900 DestroyWindow(hwnd);
10902 /* test multiline edit */
10903 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
10904 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
10905 ok(hwnd != 0, "Failed to create edit window\n");
10907 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
10908 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
10909 "wrong dlg_code %08x\n", dlg_code);
10911 ShowWindow(hwnd, SW_SHOW);
10912 UpdateWindow(hwnd);
10913 SetFocus(0);
10914 flush_sequence();
10916 SetFocus(hwnd);
10917 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
10919 SetFocus(0);
10920 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
10922 SetFocus(0);
10923 ReleaseCapture();
10924 flush_sequence();
10926 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
10927 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
10929 SetFocus(0);
10930 ReleaseCapture();
10931 flush_sequence();
10933 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
10934 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
10936 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
10937 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
10939 DestroyWindow(hwnd);
10940 DestroyWindow(parent);
10942 log_all_parent_messages--;
10945 /**************************** End of Edit test ******************************/
10947 static const struct message WmKeyDownSkippedSeq[] =
10949 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10950 { 0 }
10952 static const struct message WmKeyDownWasDownSkippedSeq[] =
10954 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
10955 { 0 }
10957 static const struct message WmKeyUpSkippedSeq[] =
10959 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10960 { 0 }
10962 static const struct message WmUserKeyUpSkippedSeq[] =
10964 { WM_USER, sent },
10965 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10966 { 0 }
10969 #define EV_STOP 0
10970 #define EV_SENDMSG 1
10971 #define EV_ACK 2
10973 struct peekmsg_info
10975 HWND hwnd;
10976 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
10979 static DWORD CALLBACK send_msg_thread_2(void *param)
10981 DWORD ret;
10982 struct peekmsg_info *info = param;
10984 trace("thread: looping\n");
10985 SetEvent(info->hevent[EV_ACK]);
10987 while (1)
10989 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
10991 switch (ret)
10993 case WAIT_OBJECT_0 + EV_STOP:
10994 trace("thread: exiting\n");
10995 return 0;
10997 case WAIT_OBJECT_0 + EV_SENDMSG:
10998 trace("thread: sending message\n");
10999 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11000 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11001 SetEvent(info->hevent[EV_ACK]);
11002 break;
11004 default:
11005 trace("unexpected return: %04x\n", ret);
11006 assert(0);
11007 break;
11010 return 0;
11013 static void test_PeekMessage(void)
11015 MSG msg;
11016 HANDLE hthread;
11017 DWORD tid, qstatus;
11018 UINT qs_all_input = QS_ALLINPUT;
11019 UINT qs_input = QS_INPUT;
11020 BOOL ret;
11021 struct peekmsg_info info;
11023 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11024 100, 100, 200, 200, 0, 0, 0, NULL);
11025 assert(info.hwnd);
11026 ShowWindow(info.hwnd, SW_SHOW);
11027 UpdateWindow(info.hwnd);
11028 SetFocus(info.hwnd);
11030 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11031 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11032 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11034 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11035 WaitForSingleObject(info.hevent[EV_ACK], 10000);
11037 flush_events();
11038 flush_sequence();
11040 SetLastError(0xdeadbeef);
11041 qstatus = GetQueueStatus(qs_all_input);
11042 if (GetLastError() == ERROR_INVALID_FLAGS)
11044 trace("QS_RAWINPUT not supported on this platform\n");
11045 qs_all_input &= ~QS_RAWINPUT;
11046 qs_input &= ~QS_RAWINPUT;
11048 if (qstatus & QS_POSTMESSAGE)
11050 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11051 qstatus = GetQueueStatus(qs_all_input);
11053 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11055 trace("signalling to send message\n");
11056 SetEvent(info.hevent[EV_SENDMSG]);
11057 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11059 /* pass invalid QS_xxxx flags */
11060 SetLastError(0xdeadbeef);
11061 qstatus = GetQueueStatus(0xffffffff);
11062 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11063 if (!qstatus)
11065 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11066 qstatus = GetQueueStatus(qs_all_input);
11068 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
11069 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11070 "wrong qstatus %08x\n", qstatus);
11072 msg.message = 0;
11073 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11074 ok(!ret,
11075 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11076 msg.message);
11077 ok_sequence(WmUser, "WmUser", FALSE);
11079 qstatus = GetQueueStatus(qs_all_input);
11080 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11082 keybd_event('N', 0, 0, 0);
11083 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11084 qstatus = GetQueueStatus(qs_all_input);
11085 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11087 skip( "queuing key events not supported\n" );
11088 goto done;
11090 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11091 /* keybd_event seems to trigger a sent message on NT4 */
11092 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11093 "wrong qstatus %08x\n", qstatus);
11095 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11096 qstatus = GetQueueStatus(qs_all_input);
11097 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11098 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11099 "wrong qstatus %08x\n", qstatus);
11101 InvalidateRect(info.hwnd, NULL, FALSE);
11102 qstatus = GetQueueStatus(qs_all_input);
11103 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11104 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
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_PAINT|QS_POSTMESSAGE|QS_KEY),
11113 "wrong qstatus %08x\n", qstatus);
11115 msg.message = 0;
11116 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11117 if (ret && msg.message == WM_CHAR)
11119 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11120 goto done;
11122 ok(!ret,
11123 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11124 msg.message);
11125 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
11127 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11128 goto done;
11130 ok_sequence(WmUser, "WmUser", FALSE);
11132 qstatus = GetQueueStatus(qs_all_input);
11133 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11134 "wrong qstatus %08x\n", qstatus);
11136 trace("signalling to send message\n");
11137 SetEvent(info.hevent[EV_SENDMSG]);
11138 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11140 qstatus = GetQueueStatus(qs_all_input);
11141 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11142 "wrong qstatus %08x\n", qstatus);
11144 msg.message = 0;
11145 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11146 ok(!ret,
11147 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11148 msg.message);
11149 ok_sequence(WmUser, "WmUser", FALSE);
11151 qstatus = GetQueueStatus(qs_all_input);
11152 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11153 "wrong qstatus %08x\n", qstatus);
11155 msg.message = 0;
11156 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11157 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11158 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11159 ret, msg.message, msg.wParam);
11160 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11162 qstatus = GetQueueStatus(qs_all_input);
11163 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11164 "wrong qstatus %08x\n", qstatus);
11166 msg.message = 0;
11167 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11168 ok(!ret,
11169 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11170 msg.message);
11171 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11173 qstatus = GetQueueStatus(qs_all_input);
11174 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11175 "wrong qstatus %08x\n", qstatus);
11177 msg.message = 0;
11178 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11179 ok(ret && msg.message == WM_PAINT,
11180 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11181 DispatchMessageA(&msg);
11182 ok_sequence(WmPaint, "WmPaint", FALSE);
11184 qstatus = GetQueueStatus(qs_all_input);
11185 ok(qstatus == MAKELONG(0, QS_KEY),
11186 "wrong qstatus %08x\n", qstatus);
11188 msg.message = 0;
11189 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11190 ok(!ret,
11191 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11192 msg.message);
11193 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11195 qstatus = GetQueueStatus(qs_all_input);
11196 ok(qstatus == MAKELONG(0, QS_KEY),
11197 "wrong qstatus %08x\n", qstatus);
11199 trace("signalling to send message\n");
11200 SetEvent(info.hevent[EV_SENDMSG]);
11201 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11203 qstatus = GetQueueStatus(qs_all_input);
11204 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11205 "wrong qstatus %08x\n", qstatus);
11207 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11209 qstatus = GetQueueStatus(qs_all_input);
11210 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11211 "wrong qstatus %08x\n", qstatus);
11213 msg.message = 0;
11214 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11215 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11216 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11217 ret, msg.message, msg.wParam);
11218 ok_sequence(WmUser, "WmUser", FALSE);
11220 qstatus = GetQueueStatus(qs_all_input);
11221 ok(qstatus == MAKELONG(0, QS_KEY),
11222 "wrong qstatus %08x\n", qstatus);
11224 msg.message = 0;
11225 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11226 ok(!ret,
11227 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11228 msg.message);
11229 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11231 qstatus = GetQueueStatus(qs_all_input);
11232 ok(qstatus == MAKELONG(0, QS_KEY),
11233 "wrong qstatus %08x\n", qstatus);
11235 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11237 qstatus = GetQueueStatus(qs_all_input);
11238 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
11239 "wrong qstatus %08x\n", qstatus);
11241 trace("signalling to send message\n");
11242 SetEvent(info.hevent[EV_SENDMSG]);
11243 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11245 qstatus = GetQueueStatus(qs_all_input);
11246 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11247 "wrong qstatus %08x\n", qstatus);
11249 msg.message = 0;
11250 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
11251 ok(!ret,
11252 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11253 msg.message);
11254 ok_sequence(WmUser, "WmUser", FALSE);
11256 qstatus = GetQueueStatus(qs_all_input);
11257 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11258 "wrong qstatus %08x\n", qstatus);
11260 msg.message = 0;
11261 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11262 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11263 else /* workaround for a missing QS_RAWINPUT support */
11264 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
11265 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11266 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11267 ret, msg.message, msg.wParam);
11268 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11270 qstatus = GetQueueStatus(qs_all_input);
11271 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11272 "wrong qstatus %08x\n", qstatus);
11274 msg.message = 0;
11275 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11276 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11277 else /* workaround for a missing QS_RAWINPUT support */
11278 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
11279 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11280 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
11281 ret, msg.message, msg.wParam);
11282 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
11284 qstatus = GetQueueStatus(qs_all_input);
11285 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11286 "wrong qstatus %08x\n", qstatus);
11288 msg.message = 0;
11289 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
11290 ok(!ret,
11291 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11292 msg.message);
11293 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11295 qstatus = GetQueueStatus(qs_all_input);
11296 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11297 "wrong qstatus %08x\n", qstatus);
11299 msg.message = 0;
11300 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11301 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11302 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11303 ret, msg.message, msg.wParam);
11304 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11306 qstatus = GetQueueStatus(qs_all_input);
11307 ok(qstatus == 0,
11308 "wrong qstatus %08x\n", qstatus);
11310 msg.message = 0;
11311 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11312 ok(!ret,
11313 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11314 msg.message);
11315 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11317 qstatus = GetQueueStatus(qs_all_input);
11318 ok(qstatus == 0,
11319 "wrong qstatus %08x\n", qstatus);
11321 /* test whether presence of the quit flag in the queue affects
11322 * the queue state
11324 PostQuitMessage(0x1234abcd);
11326 qstatus = GetQueueStatus(qs_all_input);
11327 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11328 "wrong qstatus %08x\n", qstatus);
11330 PostMessageA(info.hwnd, WM_USER, 0, 0);
11332 qstatus = GetQueueStatus(qs_all_input);
11333 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11334 "wrong qstatus %08x\n", qstatus);
11336 msg.message = 0;
11337 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11338 ok(ret && msg.message == WM_USER,
11339 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
11340 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11342 qstatus = GetQueueStatus(qs_all_input);
11343 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11344 "wrong qstatus %08x\n", qstatus);
11346 msg.message = 0;
11347 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11348 ok(ret && msg.message == WM_QUIT,
11349 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
11350 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
11351 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
11352 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11354 qstatus = GetQueueStatus(qs_all_input);
11355 todo_wine {
11356 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11357 "wrong qstatus %08x\n", qstatus);
11360 msg.message = 0;
11361 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11362 ok(!ret,
11363 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11364 msg.message);
11365 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11367 qstatus = GetQueueStatus(qs_all_input);
11368 ok(qstatus == 0,
11369 "wrong qstatus %08x\n", qstatus);
11371 /* some GetMessage tests */
11373 keybd_event('N', 0, 0, 0);
11374 qstatus = GetQueueStatus(qs_all_input);
11375 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11377 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11378 qstatus = GetQueueStatus(qs_all_input);
11379 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11381 if (qstatus)
11383 ret = GetMessageA( &msg, 0, 0, 0 );
11384 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11385 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11386 ret, msg.message, msg.wParam);
11387 qstatus = GetQueueStatus(qs_all_input);
11388 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
11391 if (qstatus)
11393 ret = GetMessageA( &msg, 0, 0, 0 );
11394 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11395 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11396 ret, msg.message, msg.wParam);
11397 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11398 qstatus = GetQueueStatus(qs_all_input);
11399 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11402 keybd_event('N', 0, 0, 0);
11403 qstatus = GetQueueStatus(qs_all_input);
11404 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11406 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11407 qstatus = GetQueueStatus(qs_all_input);
11408 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11410 if (qstatus & (QS_KEY << 16))
11412 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11413 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11414 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11415 ret, msg.message, msg.wParam);
11416 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
11417 qstatus = GetQueueStatus(qs_all_input);
11418 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11421 if (qstatus)
11423 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11424 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11425 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11426 ret, msg.message, msg.wParam);
11427 qstatus = GetQueueStatus(qs_all_input);
11428 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11431 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11432 qstatus = GetQueueStatus(qs_all_input);
11433 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11435 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11436 qstatus = GetQueueStatus(qs_all_input);
11437 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11439 trace("signalling to send message\n");
11440 SetEvent(info.hevent[EV_SENDMSG]);
11441 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11442 qstatus = GetQueueStatus(qs_all_input);
11443 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11444 "wrong qstatus %08x\n", qstatus);
11446 if (qstatus & (QS_KEY << 16))
11448 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11449 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11450 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11451 ret, msg.message, msg.wParam);
11452 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
11453 qstatus = GetQueueStatus(qs_all_input);
11454 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11457 if (qstatus)
11459 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11460 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11461 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11462 ret, msg.message, msg.wParam);
11463 qstatus = GetQueueStatus(qs_all_input);
11464 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11466 done:
11467 trace("signalling to exit\n");
11468 SetEvent(info.hevent[EV_STOP]);
11470 WaitForSingleObject(hthread, INFINITE);
11472 CloseHandle(hthread);
11473 CloseHandle(info.hevent[0]);
11474 CloseHandle(info.hevent[1]);
11475 CloseHandle(info.hevent[2]);
11477 DestroyWindow(info.hwnd);
11480 static void wait_move_event(HWND hwnd, int x, int y)
11482 MSG msg;
11483 DWORD time;
11484 BOOL ret;
11486 time = GetTickCount();
11487 while (GetTickCount() - time < 200) {
11488 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11489 if (ret && msg.pt.x > x && msg.pt.y > y) break;
11490 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
11491 else Sleep( GetTickCount() - time );
11495 #define STEP 5
11496 static void test_PeekMessage2(void)
11498 HWND hwnd;
11499 BOOL ret;
11500 MSG msg;
11501 UINT message;
11502 DWORD time1, time2, time3;
11503 int x1, y1, x2, y2, x3, y3;
11504 POINT pos;
11506 time1 = time2 = time3 = 0;
11507 x1 = y1 = x2 = y2 = x3 = y3 = 0;
11509 /* Initialise window and make sure it is ready for events */
11510 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
11511 10, 10, 800, 800, NULL, NULL, NULL, NULL);
11512 assert(hwnd);
11513 trace("Window for test_PeekMessage2 %p\n", hwnd);
11514 ShowWindow(hwnd, SW_SHOW);
11515 UpdateWindow(hwnd);
11516 SetFocus(hwnd);
11517 GetCursorPos(&pos);
11518 SetCursorPos(100, 100);
11519 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
11520 flush_events();
11522 /* Do initial mousemove, wait until we can see it
11523 and then do our test peek with PM_NOREMOVE. */
11524 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11525 wait_move_event(hwnd, 100-STEP, 100-STEP);
11527 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11528 if (!ret)
11530 skip( "queuing mouse events not supported\n" );
11531 goto done;
11533 else
11535 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
11536 message = msg.message;
11537 time1 = msg.time;
11538 x1 = msg.pt.x;
11539 y1 = msg.pt.y;
11540 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
11543 /* Allow time to advance a bit, and then simulate the user moving their
11544 * mouse around. After that we peek again with PM_NOREMOVE.
11545 * Although the previous mousemove message was never removed, the
11546 * mousemove we now peek should reflect the recent mouse movements
11547 * because the input queue will merge the move events. */
11548 Sleep(100);
11549 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11550 wait_move_event(hwnd, x1, y1);
11552 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11553 ok(ret, "no message available\n");
11554 if (ret) {
11555 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
11556 message = msg.message;
11557 time2 = msg.time;
11558 x2 = msg.pt.x;
11559 y2 = msg.pt.y;
11560 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
11561 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
11562 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
11565 /* Have another go, to drive the point home */
11566 Sleep(100);
11567 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11568 wait_move_event(hwnd, x2, y2);
11570 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11571 ok(ret, "no message available\n");
11572 if (ret) {
11573 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
11574 message = msg.message;
11575 time3 = msg.time;
11576 x3 = msg.pt.x;
11577 y3 = msg.pt.y;
11578 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
11579 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
11580 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
11583 done:
11584 DestroyWindow(hwnd);
11585 SetCursorPos(pos.x, pos.y);
11586 flush_events();
11589 static void test_PeekMessage3(void)
11591 HWND hwnd;
11592 BOOL ret;
11593 MSG msg;
11595 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
11596 10, 10, 800, 800, NULL, NULL, NULL, NULL);
11597 ok(hwnd != NULL, "expected hwnd != NULL\n");
11598 flush_events();
11600 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
11601 * were already seen. */
11603 SetTimer(hwnd, 1, 0, NULL);
11604 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
11605 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11606 PostMessageA(hwnd, WM_USER, 0, 0);
11607 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
11608 todo_wine
11609 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11610 ret = GetMessageA(&msg, NULL, 0, 0);
11611 todo_wine
11612 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11613 ret = GetMessageA(&msg, NULL, 0, 0);
11614 todo_wine
11615 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11616 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11617 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11619 SetTimer(hwnd, 1, 0, NULL);
11620 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
11621 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11622 PostMessageA(hwnd, WM_USER, 0, 0);
11623 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11624 todo_wine
11625 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11626 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11627 todo_wine
11628 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11629 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11630 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11632 /* It doesn't matter if a message range is specified or not. */
11634 SetTimer(hwnd, 1, 0, NULL);
11635 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11636 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11637 PostMessageA(hwnd, WM_USER, 0, 0);
11638 ret = GetMessageA(&msg, NULL, 0, 0);
11639 todo_wine
11640 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11641 ret = GetMessageA(&msg, NULL, 0, 0);
11642 todo_wine
11643 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11644 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11645 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11647 /* But not if the post messages were added before the PeekMessage() call. */
11649 PostMessageA(hwnd, WM_USER, 0, 0);
11650 SetTimer(hwnd, 1, 0, NULL);
11651 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11652 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11653 ret = GetMessageA(&msg, NULL, 0, 0);
11654 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11655 ret = GetMessageA(&msg, NULL, 0, 0);
11656 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11657 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11658 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11660 /* More complicated test with multiple messages. */
11662 PostMessageA(hwnd, WM_USER, 0, 0);
11663 SetTimer(hwnd, 1, 0, NULL);
11664 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11665 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11666 PostMessageA(hwnd, WM_USER + 1, 0, 0);
11667 ret = GetMessageA(&msg, NULL, 0, 0);
11668 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11669 ret = GetMessageA(&msg, NULL, 0, 0);
11670 todo_wine
11671 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11672 ret = GetMessageA(&msg, NULL, 0, 0);
11673 todo_wine
11674 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
11675 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11676 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11678 /* Also works for posted messages, but the situation is a bit different,
11679 * because both messages are in the same queue. */
11681 PostMessageA(hwnd, WM_TIMER, 0, 0);
11682 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11683 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11684 PostMessageA(hwnd, WM_USER, 0, 0);
11685 ret = GetMessageA(&msg, NULL, 0, 0);
11686 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11687 ret = GetMessageA(&msg, NULL, 0, 0);
11688 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11689 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11690 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11692 PostMessageA(hwnd, WM_USER, 0, 0);
11693 PostMessageA(hwnd, WM_TIMER, 0, 0);
11694 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11695 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11696 ret = GetMessageA(&msg, NULL, 0, 0);
11697 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11698 ret = GetMessageA(&msg, NULL, 0, 0);
11699 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11700 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11701 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11703 DestroyWindow(hwnd);
11704 flush_events();
11707 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11709 struct recvd_message msg;
11711 if (ignore_message( message )) return 0;
11713 msg.hwnd = hwnd;
11714 msg.message = message;
11715 msg.flags = sent|wparam|lparam;
11716 msg.wParam = wp;
11717 msg.lParam = lp;
11718 msg.descr = "dialog";
11719 add_message(&msg);
11721 switch (message)
11723 case WM_INITDIALOG:
11724 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
11725 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
11726 return 0;
11728 case WM_GETDLGCODE:
11729 return 0;
11731 case WM_USER:
11732 EndDialog(hwnd, 0);
11733 break;
11736 return 1;
11739 static const struct message WmQuitDialogSeq[] = {
11740 { HCBT_CREATEWND, hook },
11741 { WM_SETFONT, sent },
11742 { WM_INITDIALOG, sent },
11743 { WM_CHANGEUISTATE, sent|optional },
11744 { HCBT_DESTROYWND, hook },
11745 { 0x0090, sent|optional }, /* Vista */
11746 { WM_DESTROY, sent },
11747 { WM_NCDESTROY, sent },
11748 { 0 }
11751 static const struct message WmStopQuitSeq[] = {
11752 { WM_DWMNCRENDERINGCHANGED, posted|optional },
11753 { WM_CLOSE, posted },
11754 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
11755 { 0 }
11758 static void test_quit_message(void)
11760 MSG msg;
11761 BOOL ret;
11763 /* test using PostQuitMessage */
11764 flush_events();
11765 PostQuitMessage(0xbeef);
11767 msg.message = 0;
11768 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
11769 ok(!ret, "got %x message\n", msg.message);
11771 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
11772 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
11773 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11774 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
11776 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
11777 ok(ret, "PostMessage failed with error %d\n", GetLastError());
11779 ret = GetMessageA(&msg, NULL, 0, 0);
11780 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
11781 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
11783 /* note: WM_QUIT message received after WM_USER message */
11784 ret = GetMessageA(&msg, NULL, 0, 0);
11785 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
11786 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11787 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
11789 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11790 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
11792 /* now test with PostThreadMessage - different behaviour! */
11793 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
11795 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
11796 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
11797 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11798 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
11800 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
11801 ok(ret, "PostMessage failed with error %d\n", GetLastError());
11803 /* note: we receive the WM_QUIT message first this time */
11804 ret = GetMessageA(&msg, NULL, 0, 0);
11805 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
11806 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11807 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
11809 ret = GetMessageA(&msg, NULL, 0, 0);
11810 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
11811 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
11813 flush_events();
11814 flush_sequence();
11815 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
11816 ok(ret == 1, "expected 1, got %d\n", ret);
11817 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
11818 memset(&msg, 0xab, sizeof(msg));
11819 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11820 ok(ret, "PeekMessage failed\n");
11821 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11822 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
11823 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
11825 /* Check what happens to a WM_QUIT message posted to a window that gets
11826 * destroyed.
11828 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
11829 0, 0, 100, 100, NULL, NULL, NULL, NULL);
11830 flush_sequence();
11831 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11833 struct recvd_message rmsg;
11834 rmsg.hwnd = msg.hwnd;
11835 rmsg.message = msg.message;
11836 rmsg.flags = posted|wparam|lparam;
11837 rmsg.wParam = msg.wParam;
11838 rmsg.lParam = msg.lParam;
11839 rmsg.descr = "stop/quit";
11840 if (msg.message == WM_QUIT)
11841 /* The hwnd can only be checked here */
11842 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
11843 add_message(&rmsg);
11844 DispatchMessageA(&msg);
11846 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
11849 static const struct message WmNotifySeq[] = {
11850 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
11851 { 0 }
11854 static void test_notify_message(void)
11856 HWND hwnd;
11857 BOOL ret;
11858 MSG msg;
11860 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11861 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
11862 ok(hwnd != 0, "Failed to create window\n");
11863 flush_events();
11864 flush_sequence();
11866 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11867 ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
11868 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11870 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11871 ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
11872 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11874 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
11875 ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
11876 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11878 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
11879 ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
11880 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11882 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11883 ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
11884 flush_events();
11885 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11887 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11888 ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
11889 flush_events();
11890 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11892 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
11893 ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
11894 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11896 msg.hwnd = hwnd;
11897 DispatchMessageA(&msg);
11899 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11901 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
11902 ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
11903 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11905 msg.hwnd = hwnd;
11906 DispatchMessageA(&msg);
11908 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11910 DestroyWindow(hwnd);
11913 static const struct message WmMouseHoverSeq[] = {
11914 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
11915 { WM_MOUSEACTIVATE, sent|optional },
11916 { WM_TIMER, sent|optional }, /* XP sends it */
11917 { WM_SYSTIMER, sent },
11918 { WM_MOUSEHOVER, sent|wparam, 0 },
11919 { 0 }
11922 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
11924 MSG msg;
11925 DWORD start_ticks, end_ticks;
11927 start_ticks = GetTickCount();
11928 /* add some deviation (50%) to cover not expected delays */
11929 start_ticks += timeout / 2;
11933 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11935 /* Timer proc messages are not dispatched to the window proc,
11936 * and therefore not logged.
11938 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
11940 struct recvd_message s_msg;
11942 s_msg.hwnd = msg.hwnd;
11943 s_msg.message = msg.message;
11944 s_msg.flags = sent|wparam|lparam;
11945 s_msg.wParam = msg.wParam;
11946 s_msg.lParam = msg.lParam;
11947 s_msg.descr = "msg_loop";
11948 add_message(&s_msg);
11950 DispatchMessageA(&msg);
11953 end_ticks = GetTickCount();
11955 /* inject WM_MOUSEMOVE to see how it changes tracking */
11956 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
11958 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
11959 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
11961 inject_mouse_move = FALSE;
11963 } while (start_ticks + timeout >= end_ticks);
11966 static void test_TrackMouseEvent(void)
11968 TRACKMOUSEEVENT tme;
11969 BOOL ret;
11970 HWND hwnd, hchild;
11971 RECT rc_parent, rc_child;
11972 UINT default_hover_time, hover_width = 0, hover_height = 0;
11974 #define track_hover(track_hwnd, track_hover_time) \
11975 tme.cbSize = sizeof(tme); \
11976 tme.dwFlags = TME_HOVER; \
11977 tme.hwndTrack = track_hwnd; \
11978 tme.dwHoverTime = track_hover_time; \
11979 SetLastError(0xdeadbeef); \
11980 ret = pTrackMouseEvent(&tme); \
11981 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
11983 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
11984 tme.cbSize = sizeof(tme); \
11985 tme.dwFlags = TME_QUERY; \
11986 tme.hwndTrack = (HWND)0xdeadbeef; \
11987 tme.dwHoverTime = 0xdeadbeef; \
11988 SetLastError(0xdeadbeef); \
11989 ret = pTrackMouseEvent(&tme); \
11990 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
11991 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
11992 ok(tme.dwFlags == (expected_track_flags), \
11993 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
11994 ok(tme.hwndTrack == (expected_track_hwnd), \
11995 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
11996 ok(tme.dwHoverTime == (expected_hover_time), \
11997 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
11999 #define track_hover_cancel(track_hwnd) \
12000 tme.cbSize = sizeof(tme); \
12001 tme.dwFlags = TME_HOVER | TME_CANCEL; \
12002 tme.hwndTrack = track_hwnd; \
12003 tme.dwHoverTime = 0xdeadbeef; \
12004 SetLastError(0xdeadbeef); \
12005 ret = pTrackMouseEvent(&tme); \
12006 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12008 default_hover_time = 0xdeadbeef;
12009 SetLastError(0xdeadbeef);
12010 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12011 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12012 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12013 if (!ret) default_hover_time = 400;
12014 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12016 SetLastError(0xdeadbeef);
12017 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12018 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12019 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12020 if (!ret) hover_width = 4;
12021 SetLastError(0xdeadbeef);
12022 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12023 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12024 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12025 if (!ret) hover_height = 4;
12026 trace("hover rect is %u x %d\n", hover_width, hover_height);
12028 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12029 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12030 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12031 NULL, NULL, 0);
12032 assert(hwnd);
12034 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12035 WS_CHILD | WS_BORDER | WS_VISIBLE,
12036 50, 50, 200, 200, hwnd,
12037 NULL, NULL, 0);
12038 assert(hchild);
12040 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12041 flush_events();
12042 flush_sequence();
12044 tme.cbSize = 0;
12045 tme.dwFlags = TME_QUERY;
12046 tme.hwndTrack = (HWND)0xdeadbeef;
12047 tme.dwHoverTime = 0xdeadbeef;
12048 SetLastError(0xdeadbeef);
12049 ret = pTrackMouseEvent(&tme);
12050 ok(!ret, "TrackMouseEvent should fail\n");
12051 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12052 "not expected error %u\n", GetLastError());
12054 tme.cbSize = sizeof(tme);
12055 tme.dwFlags = TME_HOVER;
12056 tme.hwndTrack = (HWND)0xdeadbeef;
12057 tme.dwHoverTime = 0xdeadbeef;
12058 SetLastError(0xdeadbeef);
12059 ret = pTrackMouseEvent(&tme);
12060 ok(!ret, "TrackMouseEvent should fail\n");
12061 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12062 "not expected error %u\n", GetLastError());
12064 tme.cbSize = sizeof(tme);
12065 tme.dwFlags = TME_HOVER | TME_CANCEL;
12066 tme.hwndTrack = (HWND)0xdeadbeef;
12067 tme.dwHoverTime = 0xdeadbeef;
12068 SetLastError(0xdeadbeef);
12069 ret = pTrackMouseEvent(&tme);
12070 ok(!ret, "TrackMouseEvent should fail\n");
12071 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12072 "not expected error %u\n", GetLastError());
12074 GetWindowRect(hwnd, &rc_parent);
12075 GetWindowRect(hchild, &rc_child);
12076 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12078 /* Process messages so that the system updates its internal current
12079 * window and hittest, otherwise TrackMouseEvent calls don't have any
12080 * effect.
12082 flush_events();
12083 flush_sequence();
12085 track_query(0, NULL, 0);
12086 track_hover(hchild, 0);
12087 track_query(0, NULL, 0);
12089 flush_events();
12090 flush_sequence();
12092 track_hover(hwnd, 0);
12093 tme.cbSize = sizeof(tme);
12094 tme.dwFlags = TME_QUERY;
12095 tme.hwndTrack = (HWND)0xdeadbeef;
12096 tme.dwHoverTime = 0xdeadbeef;
12097 SetLastError(0xdeadbeef);
12098 ret = pTrackMouseEvent(&tme);
12099 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12100 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12101 if (!tme.dwFlags)
12103 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12104 DestroyWindow( hwnd );
12105 return;
12107 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12108 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12109 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12110 tme.dwHoverTime, default_hover_time);
12112 pump_msg_loop_timeout(default_hover_time, FALSE);
12113 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12115 track_query(0, NULL, 0);
12117 track_hover(hwnd, HOVER_DEFAULT);
12118 track_query(TME_HOVER, hwnd, default_hover_time);
12120 Sleep(default_hover_time / 2);
12121 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12122 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12124 track_query(TME_HOVER, hwnd, default_hover_time);
12126 pump_msg_loop_timeout(default_hover_time, FALSE);
12127 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12129 track_query(0, NULL, 0);
12131 track_hover(hwnd, HOVER_DEFAULT);
12132 track_query(TME_HOVER, hwnd, default_hover_time);
12134 pump_msg_loop_timeout(default_hover_time, TRUE);
12135 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12137 track_query(0, NULL, 0);
12139 track_hover(hwnd, HOVER_DEFAULT);
12140 track_query(TME_HOVER, hwnd, default_hover_time);
12141 track_hover_cancel(hwnd);
12143 DestroyWindow(hwnd);
12145 #undef track_hover
12146 #undef track_query
12147 #undef track_hover_cancel
12151 static const struct message WmSetWindowRgn[] = {
12152 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12153 { WM_NCCALCSIZE, sent|wparam, 1 },
12154 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12155 { WM_GETTEXT, sent|defwinproc|optional },
12156 { WM_ERASEBKGND, sent|optional },
12157 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12158 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12159 { 0 }
12162 static const struct message WmSetWindowRgn_no_redraw[] = {
12163 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12164 { WM_NCCALCSIZE, sent|wparam, 1 },
12165 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12166 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12167 { 0 }
12170 static const struct message WmSetWindowRgn_clear[] = {
12171 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12172 { WM_NCCALCSIZE, sent|wparam, 1 },
12173 { WM_NCPAINT, sent|optional },
12174 { WM_GETTEXT, sent|defwinproc|optional },
12175 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
12176 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12177 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
12178 { WM_NCPAINT, sent|optional },
12179 { WM_GETTEXT, sent|defwinproc|optional },
12180 { WM_ERASEBKGND, sent|optional },
12181 { WM_WINDOWPOSCHANGING, sent|optional },
12182 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12183 { WM_NCPAINT, sent|optional },
12184 { WM_GETTEXT, sent|defwinproc|optional },
12185 { WM_ERASEBKGND, sent|optional },
12186 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12187 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12188 { WM_NCPAINT, sent|optional },
12189 { WM_GETTEXT, sent|defwinproc|optional },
12190 { WM_ERASEBKGND, sent|optional },
12191 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12192 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12193 { 0 }
12196 static void test_SetWindowRgn(void)
12198 HRGN hrgn;
12199 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
12200 100, 100, 200, 200, 0, 0, 0, NULL);
12201 ok( hwnd != 0, "Failed to create overlapped window\n" );
12203 ShowWindow( hwnd, SW_SHOW );
12204 UpdateWindow( hwnd );
12205 flush_events();
12206 flush_sequence();
12208 trace("testing SetWindowRgn\n");
12209 hrgn = CreateRectRgn( 0, 0, 150, 150 );
12210 SetWindowRgn( hwnd, hrgn, TRUE );
12211 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
12213 hrgn = CreateRectRgn( 30, 30, 160, 160 );
12214 SetWindowRgn( hwnd, hrgn, FALSE );
12215 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
12217 hrgn = CreateRectRgn( 0, 0, 180, 180 );
12218 SetWindowRgn( hwnd, hrgn, TRUE );
12219 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
12221 SetWindowRgn( hwnd, 0, TRUE );
12222 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
12224 DestroyWindow( hwnd );
12227 /*************************** ShowWindow() test ******************************/
12228 static const struct message WmShowNormal[] = {
12229 { WM_SHOWWINDOW, sent|wparam, 1 },
12230 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12231 { HCBT_ACTIVATE, hook },
12232 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12233 { HCBT_SETFOCUS, hook },
12234 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12235 { 0 }
12237 static const struct message WmShow[] = {
12238 { WM_SHOWWINDOW, sent|wparam, 1 },
12239 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12240 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12241 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12242 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12243 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12244 { 0 }
12246 static const struct message WmShowNoActivate_1[] = {
12247 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12248 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12249 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12250 { WM_MOVE, sent|defwinproc|optional },
12251 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12252 { 0 }
12254 static const struct message WmShowNoActivate_2[] = {
12255 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12256 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12257 { HCBT_ACTIVATE, hook|optional },
12258 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12259 { HCBT_SETFOCUS, hook|optional },
12260 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12261 { WM_MOVE, sent|defwinproc },
12262 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12263 { HCBT_SETFOCUS, hook|optional },
12264 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12265 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12266 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12267 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12268 { 0 }
12270 static const struct message WmShowNA_1[] = {
12271 { WM_SHOWWINDOW, sent|wparam, 1 },
12272 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12273 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12274 { 0 }
12276 static const struct message WmShowNA_2[] = {
12277 { WM_SHOWWINDOW, sent|wparam, 1 },
12278 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12279 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12280 { 0 }
12282 static const struct message WmRestore_1[] = {
12283 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12284 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12285 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12286 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12287 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12288 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12289 { WM_MOVE, sent|defwinproc },
12290 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12291 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12292 { 0 }
12294 static const struct message WmRestore_2[] = {
12295 { WM_SHOWWINDOW, sent|wparam, 1 },
12296 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12297 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12298 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12299 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12300 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12301 { 0 }
12303 static const struct message WmRestore_3[] = {
12304 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12305 { WM_GETMINMAXINFO, sent },
12306 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12307 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12308 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12309 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12310 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12311 { WM_MOVE, sent|defwinproc },
12312 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12313 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12314 { 0 }
12316 static const struct message WmRestore_4[] = {
12317 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
12318 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12319 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12320 { WM_MOVE, sent|defwinproc|optional },
12321 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12322 { 0 }
12324 static const struct message WmRestore_5[] = {
12325 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
12326 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12327 { HCBT_ACTIVATE, hook|optional },
12328 { HCBT_SETFOCUS, hook|optional },
12329 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12330 { WM_MOVE, sent|defwinproc|optional },
12331 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12332 { 0 }
12334 static const struct message WmHide_1[] = {
12335 { WM_SHOWWINDOW, sent|wparam, 0 },
12336 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
12337 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
12338 { HCBT_ACTIVATE, hook|optional },
12339 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12340 { 0 }
12342 static const struct message WmHide_2[] = {
12343 { WM_SHOWWINDOW, sent|wparam, 0 },
12344 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12345 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12346 { HCBT_ACTIVATE, hook|optional },
12347 { 0 }
12349 static const struct message WmHide_3[] = {
12350 { WM_SHOWWINDOW, sent|wparam, 0 },
12351 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12352 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12353 { HCBT_SETFOCUS, hook|optional },
12354 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12355 { 0 }
12357 static const struct message WmShowMinimized_1[] = {
12358 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12359 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12360 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12361 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12362 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12363 { WM_MOVE, sent|defwinproc },
12364 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12365 { 0 }
12367 static const struct message WmMinimize_1[] = {
12368 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12369 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12370 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12371 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12372 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12373 { WM_MOVE, sent|defwinproc },
12374 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12375 { 0 }
12377 static const struct message WmMinimize_2[] = {
12378 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12379 { HCBT_SETFOCUS, hook|optional },
12380 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12381 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12382 { WM_MOVE, sent|defwinproc },
12383 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12384 { 0 }
12386 static const struct message WmMinimize_3[] = {
12387 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12388 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12389 { HCBT_ACTIVATE, hook|optional },
12390 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12391 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12392 { WM_MOVE, sent|defwinproc },
12393 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12394 { 0 }
12396 static const struct message WmShowMinNoActivate[] = {
12397 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12398 { WM_WINDOWPOSCHANGING, sent },
12399 { WM_WINDOWPOSCHANGED, sent },
12400 { WM_MOVE, sent|defwinproc|optional },
12401 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12402 { 0 }
12404 static const struct message WmMinMax_1[] = {
12405 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12406 { 0 }
12408 static const struct message WmMinMax_2[] = {
12409 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12410 { WM_GETMINMAXINFO, sent|optional },
12411 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
12412 { HCBT_ACTIVATE, hook|optional },
12413 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12414 { HCBT_SETFOCUS, hook|optional },
12415 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12416 { WM_MOVE, sent|defwinproc|optional },
12417 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
12418 { HCBT_SETFOCUS, hook|optional },
12419 { 0 }
12421 static const struct message WmMinMax_3[] = {
12422 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12423 { HCBT_SETFOCUS, hook|optional },
12424 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12425 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12426 { WM_MOVE, sent|defwinproc|optional },
12427 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12428 { 0 }
12430 static const struct message WmMinMax_4[] = {
12431 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12432 { 0 }
12434 static const struct message WmShowMaximized_1[] = {
12435 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12436 { WM_GETMINMAXINFO, sent },
12437 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12438 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12439 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12440 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12441 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12442 { WM_MOVE, sent|defwinproc },
12443 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12444 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12445 { 0 }
12447 static const struct message WmShowMaximized_2[] = {
12448 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12449 { WM_GETMINMAXINFO, sent },
12450 { WM_WINDOWPOSCHANGING, sent|optional },
12451 { HCBT_ACTIVATE, hook|optional },
12452 { WM_WINDOWPOSCHANGED, sent|optional },
12453 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
12454 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
12455 { WM_WINDOWPOSCHANGING, sent|optional },
12456 { HCBT_SETFOCUS, hook|optional },
12457 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12458 { WM_MOVE, sent|defwinproc },
12459 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12460 { HCBT_SETFOCUS, hook|optional },
12461 { 0 }
12463 static const struct message WmShowMaximized_3[] = {
12464 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12465 { WM_GETMINMAXINFO, sent|optional },
12466 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12467 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12468 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12469 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12470 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12471 { WM_MOVE, sent|defwinproc|optional },
12472 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12473 { 0 }
12476 static void test_ShowWindow(void)
12478 /* ShowWindow commands in random order */
12479 static const struct
12481 INT cmd; /* ShowWindow command */
12482 LPARAM ret; /* ShowWindow return value */
12483 DWORD style; /* window style after the command */
12484 const struct message *msg; /* message sequence the command produces */
12485 INT wp_cmd, wp_flags; /* window placement after the command */
12486 POINT wp_min, wp_max; /* window placement after the command */
12487 BOOL todo_msg; /* message sequence doesn't match what Wine does */
12488 } sw[] =
12490 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
12491 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12492 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
12493 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12494 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
12495 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12496 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12497 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12498 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
12499 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12500 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
12501 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12502 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
12503 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12504 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12505 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12506 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
12507 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12508 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
12509 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12510 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
12511 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12512 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
12513 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12514 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
12515 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12516 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
12517 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12518 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
12519 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12520 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12521 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12522 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
12523 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12524 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
12525 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12526 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
12527 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12528 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
12529 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12530 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12531 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12532 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
12533 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
12534 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
12535 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12536 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12537 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12538 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12539 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12540 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
12541 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12542 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
12543 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12544 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12545 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12546 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12547 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12548 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
12549 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12550 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
12551 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12552 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
12553 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12554 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12555 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12556 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
12557 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12558 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
12559 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12560 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12561 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12562 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
12563 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12564 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
12565 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12566 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
12567 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12568 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
12569 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12570 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
12571 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12572 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
12573 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12574 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
12575 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12576 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
12577 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12578 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
12579 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12580 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
12581 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12582 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
12583 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12584 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
12585 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12586 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
12587 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12588 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
12589 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12590 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
12591 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12592 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
12593 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12594 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12595 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12596 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
12597 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12598 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12599 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12600 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
12601 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12602 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
12603 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
12605 HWND hwnd;
12606 DWORD style;
12607 LPARAM ret;
12608 INT i;
12609 WINDOWPLACEMENT wp;
12610 RECT win_rc, work_rc = {0, 0, 0, 0};
12612 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
12613 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
12614 120, 120, 90, 90,
12615 0, 0, 0, NULL);
12616 assert(hwnd);
12618 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
12619 ok(style == 0, "expected style 0, got %08x\n", style);
12621 flush_events();
12622 flush_sequence();
12624 if (pGetMonitorInfoA && pMonitorFromPoint)
12626 HMONITOR hmon;
12627 MONITORINFO mi;
12628 POINT pt = {0, 0};
12630 SetLastError(0xdeadbeef);
12631 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
12632 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
12634 mi.cbSize = sizeof(mi);
12635 SetLastError(0xdeadbeef);
12636 ret = pGetMonitorInfoA(hmon, &mi);
12637 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
12638 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
12639 wine_dbgstr_rect(&mi.rcWork));
12640 work_rc = mi.rcWork;
12643 GetWindowRect(hwnd, &win_rc);
12644 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
12646 wp.length = sizeof(wp);
12647 SetLastError(0xdeadbeaf);
12648 ret = GetWindowPlacement(hwnd, &wp);
12649 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
12650 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
12651 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
12652 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
12653 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
12654 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
12655 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
12656 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
12657 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
12658 wine_dbgstr_rect(&wp.rcNormalPosition));
12660 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
12662 static const char * const sw_cmd_name[13] =
12664 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
12665 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
12666 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
12667 "SW_NORMALNA" /* 0xCC */
12669 char comment[64];
12670 INT idx; /* index into the above array of names */
12672 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
12674 style = GetWindowLongA(hwnd, GWL_STYLE);
12675 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
12676 ret = ShowWindow(hwnd, sw[i].cmd);
12677 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
12678 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
12679 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
12681 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
12682 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
12684 wp.length = sizeof(wp);
12685 SetLastError(0xdeadbeaf);
12686 ret = GetWindowPlacement(hwnd, &wp);
12687 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
12688 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
12689 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
12691 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
12692 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
12693 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
12695 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
12696 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
12697 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
12699 else
12701 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
12702 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
12705 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
12706 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
12707 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
12709 if (0) /* FIXME: Wine behaves completely different here */
12710 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
12711 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
12713 DestroyWindow(hwnd);
12714 flush_events();
12717 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12719 struct recvd_message msg;
12721 if (ignore_message( message )) return 0;
12723 msg.hwnd = hwnd;
12724 msg.message = message;
12725 msg.flags = sent|wparam|lparam;
12726 msg.wParam = wParam;
12727 msg.lParam = lParam;
12728 msg.descr = "dialog";
12729 add_message(&msg);
12731 /* calling DefDlgProc leads to a recursion under XP */
12733 switch (message)
12735 case WM_INITDIALOG:
12736 case WM_GETDLGCODE:
12737 return 0;
12739 return 1;
12742 static WNDPROC orig_edit_proc;
12743 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12745 struct recvd_message msg;
12747 if (ignore_message( message )) return 0;
12749 msg.hwnd = hwnd;
12750 msg.message = message;
12751 msg.flags = sent|wparam|lparam;
12752 msg.wParam = wp;
12753 msg.lParam = lp;
12754 msg.descr = "edit";
12755 add_message(&msg);
12757 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
12760 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12762 struct recvd_message msg;
12764 if (ignore_message( message )) return 0;
12766 msg.hwnd = hwnd;
12767 msg.message = message;
12768 msg.flags = sent|wparam|lparam|parent;
12769 msg.wParam = wParam;
12770 msg.lParam = lParam;
12771 msg.descr = "dialog";
12772 add_message(&msg);
12774 if (message == WM_INITDIALOG)
12776 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
12777 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
12780 return 1;
12783 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12785 ok( 0, "should not be called since DefDlgProc is not used\n" );
12786 return 0;
12789 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12791 struct recvd_message msg;
12793 if (!ignore_message( message ))
12795 msg.hwnd = hwnd;
12796 msg.message = message;
12797 msg.flags = sent|wparam|lparam|parent;
12798 msg.wParam = wParam;
12799 msg.lParam = lParam;
12800 msg.descr = "dialog";
12801 add_message(&msg);
12803 if (message == WM_INITDIALOG)
12805 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
12806 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
12807 return 1;
12809 return DefWindowProcW( hwnd, message, wParam, lParam );
12812 static const struct message WmDefDlgSetFocus_1[] = {
12813 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12814 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
12815 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
12816 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
12817 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
12818 { HCBT_SETFOCUS, hook },
12819 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
12820 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12821 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12822 { WM_SETFOCUS, sent|wparam, 0 },
12823 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12824 { WM_CTLCOLOREDIT, sent },
12825 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12826 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12827 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12828 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12829 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
12830 { 0 }
12832 static const struct message WmDefDlgSetFocus_2[] = {
12833 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12834 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
12835 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
12836 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
12837 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
12838 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12839 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
12840 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12841 { 0 }
12843 /* Creation of a dialog */
12844 static const struct message WmCreateDialogParamSeq_1[] = {
12845 { HCBT_CREATEWND, hook },
12846 { WM_NCCREATE, sent },
12847 { WM_NCCALCSIZE, sent|wparam, 0 },
12848 { WM_CREATE, sent },
12849 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
12850 { WM_SIZE, sent|wparam, SIZE_RESTORED },
12851 { WM_MOVE, sent },
12852 { WM_SETFONT, sent },
12853 { WM_INITDIALOG, sent },
12854 { WM_CHANGEUISTATE, sent|optional },
12855 { 0 }
12857 /* Creation of a dialog */
12858 static const struct message WmCreateDialogParamSeq_2[] = {
12859 { HCBT_CREATEWND, hook },
12860 { WM_NCCREATE, sent },
12861 { WM_NCCALCSIZE, sent|wparam, 0 },
12862 { WM_CREATE, sent },
12863 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
12864 { WM_SIZE, sent|wparam, SIZE_RESTORED },
12865 { WM_MOVE, sent },
12866 { WM_CHANGEUISTATE, sent|optional },
12867 { 0 }
12870 static const struct message WmCreateDialogParamSeq_3[] = {
12871 { HCBT_CREATEWND, hook },
12872 { WM_SETFONT, sent|parent },
12873 { WM_INITDIALOG, sent|parent },
12874 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12875 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
12876 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12877 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12878 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12879 { HCBT_ACTIVATE, hook },
12880 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
12881 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12882 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12883 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
12884 { WM_NCACTIVATE, sent|parent },
12885 { WM_ACTIVATE, sent|parent|wparam, 1 },
12886 { WM_SETFOCUS, sent },
12887 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
12888 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12889 { WM_USER, sent|parent },
12890 { WM_CHANGEUISTATE, sent|parent|optional },
12891 { 0 }
12894 static const struct message WmCreateDialogParamSeq_4[] = {
12895 { HCBT_CREATEWND, hook },
12896 { WM_NCCREATE, sent|parent },
12897 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
12898 { WM_CREATE, sent|parent },
12899 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
12900 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
12901 { WM_MOVE, sent|parent },
12902 { WM_SETFONT, sent|parent },
12903 { WM_INITDIALOG, sent|parent },
12904 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12905 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
12906 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12907 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12908 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12909 { HCBT_ACTIVATE, hook },
12910 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
12911 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12912 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12913 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
12914 { WM_NCACTIVATE, sent|parent },
12915 { WM_ACTIVATE, sent|parent|wparam, 1 },
12916 { HCBT_SETFOCUS, hook },
12917 { WM_SETFOCUS, sent|parent },
12918 { WM_KILLFOCUS, sent|parent },
12919 { WM_SETFOCUS, sent },
12920 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
12921 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12922 { WM_USER, sent|parent },
12923 { WM_CHANGEUISTATE, sent|parent|optional },
12924 { WM_UPDATEUISTATE, sent|parent|optional },
12925 { WM_UPDATEUISTATE, sent|optional },
12926 { 0 }
12929 static void test_dialog_messages(void)
12931 WNDCLASSA cls;
12932 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
12933 LRESULT ret;
12935 #define set_selection(hctl, start, end) \
12936 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
12937 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
12939 #define check_selection(hctl, start, end) \
12940 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
12941 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
12943 subclass_edit();
12945 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
12946 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
12947 0, 0, 100, 100, 0, 0, 0, NULL);
12948 ok(hdlg != 0, "Failed to create custom dialog window\n");
12950 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
12951 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
12952 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
12953 ok(hedit1 != 0, "Failed to create edit control\n");
12954 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
12955 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
12956 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
12957 ok(hedit2 != 0, "Failed to create edit control\n");
12959 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
12960 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
12962 hfocus = GetFocus();
12963 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
12965 SetFocus(hedit2);
12966 hfocus = GetFocus();
12967 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
12969 check_selection(hedit1, 0, 0);
12970 check_selection(hedit2, 0, 0);
12972 set_selection(hedit2, 0, -1);
12973 check_selection(hedit2, 0, 3);
12975 SetFocus(0);
12976 hfocus = GetFocus();
12977 ok(hfocus == 0, "wrong focus %p\n", hfocus);
12979 flush_sequence();
12980 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
12981 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
12982 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
12984 hfocus = GetFocus();
12985 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
12987 check_selection(hedit1, 0, 5);
12988 check_selection(hedit2, 0, 3);
12990 flush_sequence();
12991 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
12992 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
12993 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
12995 hfocus = GetFocus();
12996 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
12998 check_selection(hedit1, 0, 5);
12999 check_selection(hedit2, 0, 3);
13001 EndDialog(hdlg, 0);
13002 DestroyWindow(hedit1);
13003 DestroyWindow(hedit2);
13004 DestroyWindow(hdlg);
13005 flush_sequence();
13007 #undef set_selection
13008 #undef check_selection
13010 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13011 cls.lpszClassName = "MyDialogClass";
13012 cls.hInstance = GetModuleHandleA(NULL);
13013 /* need a cast since a dlgproc is used as a wndproc */
13014 cls.lpfnWndProc = test_dlg_proc;
13015 if (!RegisterClassA(&cls)) assert(0);
13017 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13018 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13019 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13020 EndDialog(hdlg, 0);
13021 DestroyWindow(hdlg);
13022 flush_sequence();
13024 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13025 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13026 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13027 EndDialog(hdlg, 0);
13028 DestroyWindow(hdlg);
13029 flush_sequence();
13031 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13032 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13033 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13034 EndDialog(hdlg, 0);
13035 DestroyWindow(hdlg);
13036 flush_sequence();
13038 UnregisterClassA( cls.lpszClassName, cls.hInstance );
13039 cls.lpfnWndProc = test_dlg_proc4;
13040 ok( RegisterClassA(&cls), "failed to register class again\n" );
13041 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13042 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13043 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13044 EndDialog(hdlg, 0);
13045 DestroyWindow(hdlg);
13046 flush_sequence();
13048 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13050 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13051 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13052 100, 100, 200, 200, 0, 0, 0, NULL);
13053 ok (parent != 0, "Failed to create parent window\n");
13055 /* This child has no parent set. We will later call SetParent on it,
13056 * so that it will have a parent set, but no WS_CHILD style. */
13057 child = CreateWindowExA(0, "TestWindowClass", "Test child",
13058 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13059 100, 100, 200, 200, 0, 0, 0, NULL);
13060 ok (child != 0, "Failed to create child window\n");
13062 /* This is a regular child window. When used as an owner, the other
13063 * child window will be used. */
13064 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13065 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13066 100, 100, 200, 200, child, 0, 0, NULL);
13067 ok (child2 != 0, "Failed to create child window\n");
13069 SetParent(child, parent);
13070 SetFocus(child);
13072 flush_sequence();
13073 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13074 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13076 DestroyWindow(child2);
13077 DestroyWindow(child);
13078 DestroyWindow(parent);
13079 flush_sequence();
13082 static void test_enddialog_seq(HWND dialog, HWND owner)
13084 const struct message seq[] = {
13085 { WM_ENABLE, sent },
13086 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13087 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13088 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13089 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13090 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13091 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13092 { WM_QUERYNEWPALETTE, sent|optional },
13093 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13094 { WM_GETTEXT, sent|optional|defwinproc },
13095 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13096 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13097 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13098 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13099 { 0 }
13102 flush_sequence();
13103 EndDialog(dialog, 0);
13104 ok_sequence(seq, "EndDialog", FALSE);
13107 static void test_enddialog_seq2(HWND dialog, HWND owner)
13109 const struct message seq[] = {
13110 { WM_ENABLE, parent|sent },
13111 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13112 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13113 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13114 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13115 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13116 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13117 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13118 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13119 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13120 { 0 }
13123 flush_sequence();
13124 EndDialog(dialog, 0);
13125 ok_sequence(seq, "EndDialog2", FALSE);
13128 static void test_EndDialog(void)
13130 HWND hparent, hother, hactive, hdlg, hchild;
13131 WNDCLASSA cls;
13133 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13134 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13135 100, 100, 200, 200, 0, 0, 0, NULL);
13136 ok (hparent != 0, "Failed to create parent window\n");
13138 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
13139 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13140 200, 100, 200, 200, 0, 0, 0, NULL);
13141 ok (hother != 0, "Failed to create parent window\n");
13143 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13144 cls.lpszClassName = "MyDialogClass";
13145 cls.hInstance = GetModuleHandleA(NULL);
13146 cls.lpfnWndProc = test_dlg_proc;
13147 if (!RegisterClassA(&cls)) assert(0);
13149 flush_sequence();
13150 SetForegroundWindow(hother);
13151 hactive = GetForegroundWindow();
13152 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
13154 /* create a dialog where the parent is disabled, this parent should be
13155 * enabled and receive focus when dialog exits */
13156 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
13157 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13158 SetForegroundWindow(hdlg);
13159 hactive = GetForegroundWindow();
13160 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
13161 EndDialog(hdlg, 0);
13162 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13163 hactive = GetForegroundWindow();
13164 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13165 DestroyWindow(hdlg);
13166 flush_sequence();
13168 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
13169 EnableWindow(hparent, FALSE);
13170 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
13171 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13172 0, 0, 100, 100, hparent, 0, 0, NULL);
13173 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13174 flush_sequence();
13175 SetForegroundWindow(hother);
13176 flush_sequence();
13177 hactive = GetForegroundWindow();
13178 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
13179 hactive = GetActiveWindow();
13180 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
13181 EndDialog(hdlg, 0);
13182 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13183 hactive = GetForegroundWindow();
13184 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13185 DestroyWindow(hdlg);
13186 flush_sequence();
13188 DestroyWindow( hparent );
13190 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13191 WS_POPUP | WS_VISIBLE | WS_DISABLED,
13192 100, 100, 200, 200, 0, 0, 0, NULL);
13193 ok (hparent != 0, "Failed to create parent window\n");
13195 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
13196 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13197 0, 0, 0, 0, 0, 0, 0, NULL);
13198 ok (hchild != 0, "Failed to create child window\n");
13200 SetParent(hchild, hparent);
13202 flush_sequence();
13203 SetForegroundWindow(hother);
13204 hactive = GetForegroundWindow();
13205 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13207 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13208 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13210 SetForegroundWindow(hdlg);
13211 test_enddialog_seq(hdlg, hchild);
13213 hactive = GetForegroundWindow();
13214 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13216 DestroyWindow(hdlg);
13218 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
13219 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
13221 SetForegroundWindow(hother);
13222 hactive = GetForegroundWindow();
13223 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13225 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13226 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13228 SetForegroundWindow(hdlg);
13229 test_enddialog_seq2(hdlg, hparent);
13231 hactive = GetForegroundWindow();
13232 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13233 DestroyWindow(hdlg);
13234 DestroyWindow(hchild);
13235 DestroyWindow(hparent);
13236 DestroyWindow(hother);
13237 flush_sequence();
13239 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13242 static void test_nullCallback(void)
13244 HWND hwnd;
13246 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13247 100, 100, 200, 200, 0, 0, 0, NULL);
13248 ok (hwnd != 0, "Failed to create overlapped window\n");
13250 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
13251 flush_events();
13252 DestroyWindow(hwnd);
13255 /* SetActiveWindow( 0 ) hwnd visible */
13256 static const struct message SetActiveWindowSeq0[] =
13258 { HCBT_ACTIVATE, hook|optional },
13259 { WM_NCACTIVATE, sent|wparam, 0 },
13260 { WM_GETTEXT, sent|defwinproc|optional },
13261 { WM_ACTIVATE, sent|wparam, 0 },
13262 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13263 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13264 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13265 { WM_KILLFOCUS, sent|optional },
13266 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13267 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13268 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13269 { WM_GETTEXT, sent|defwinproc|optional },
13270 { WM_ACTIVATE, sent|wparam|optional, 1 },
13271 { HCBT_SETFOCUS, hook|optional },
13272 { WM_KILLFOCUS, sent|defwinproc|optional },
13273 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13274 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13275 { WM_IME_SETCONTEXT, sent|optional },
13276 { WM_IME_SETCONTEXT, sent|optional },
13277 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13278 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13279 { WM_SETFOCUS, sent|defwinproc|optional },
13280 { WM_GETTEXT, sent|optional },
13281 { 0 }
13283 /* SetActiveWindow( hwnd ) hwnd visible */
13284 static const struct message SetActiveWindowSeq1[] =
13286 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13287 { 0 }
13289 /* SetActiveWindow( popup ) hwnd visible, popup visible */
13290 static const struct message SetActiveWindowSeq2[] =
13292 { HCBT_ACTIVATE, hook },
13293 { WM_NCACTIVATE, sent|wparam, 0 },
13294 { WM_GETTEXT, sent|defwinproc|optional },
13295 { WM_ACTIVATE, sent|wparam, 0 },
13296 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13297 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13298 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13299 { WM_NCPAINT, sent|optional },
13300 { WM_GETTEXT, sent|defwinproc|optional },
13301 { WM_ERASEBKGND, sent|optional },
13302 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13303 { WM_NCACTIVATE, sent|wparam, 1 },
13304 { WM_GETTEXT, sent|defwinproc|optional },
13305 { WM_ACTIVATE, sent|wparam, 1 },
13306 { HCBT_SETFOCUS, hook },
13307 { WM_KILLFOCUS, sent|defwinproc },
13308 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13309 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13310 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13311 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13312 { WM_SETFOCUS, sent|defwinproc },
13313 { WM_GETTEXT, sent|optional },
13314 { 0 }
13317 /* SetActiveWindow( hwnd ) hwnd not visible */
13318 static const struct message SetActiveWindowSeq3[] =
13320 { HCBT_ACTIVATE, hook },
13321 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13322 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13323 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13324 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13325 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13326 { WM_ACTIVATEAPP, sent|wparam, 1 },
13327 { WM_ACTIVATEAPP, sent|wparam, 1 },
13328 { WM_NCACTIVATE, sent|wparam, 1 },
13329 { WM_ACTIVATE, sent|wparam, 1 },
13330 { HCBT_SETFOCUS, hook },
13331 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13332 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13333 { WM_SETFOCUS, sent|defwinproc },
13334 { 0 }
13336 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
13337 static const struct message SetActiveWindowSeq4[] =
13339 { HCBT_ACTIVATE, hook },
13340 { WM_NCACTIVATE, sent|wparam, 0 },
13341 { WM_GETTEXT, sent|defwinproc|optional },
13342 { WM_ACTIVATE, sent|wparam, 0 },
13343 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13344 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13345 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13346 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13347 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13348 { WM_NCACTIVATE, sent|wparam, 1 },
13349 { WM_GETTEXT, sent|defwinproc|optional },
13350 { WM_ACTIVATE, sent|wparam, 1 },
13351 { HCBT_SETFOCUS, hook },
13352 { WM_KILLFOCUS, sent|defwinproc },
13353 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13354 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13355 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13356 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13357 { WM_SETFOCUS, sent|defwinproc },
13358 { 0 }
13362 static void test_SetActiveWindow(void)
13364 HWND hwnd, popup, ret;
13366 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13367 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13368 100, 100, 200, 200, 0, 0, 0, NULL);
13370 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13371 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
13372 100, 100, 200, 200, hwnd, 0, 0, NULL);
13374 ok(hwnd != 0, "Failed to create overlapped window\n");
13375 ok(popup != 0, "Failed to create popup window\n");
13376 SetForegroundWindow( popup );
13377 flush_sequence();
13379 trace("SetActiveWindow(0)\n");
13380 ret = SetActiveWindow(0);
13381 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
13382 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
13383 flush_sequence();
13385 trace("SetActiveWindow(hwnd), hwnd visible\n");
13386 ret = SetActiveWindow(hwnd);
13387 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
13388 flush_sequence();
13390 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
13391 ret = SetActiveWindow(popup);
13392 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
13393 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
13394 flush_sequence();
13396 ShowWindow(hwnd, SW_HIDE);
13397 ShowWindow(popup, SW_HIDE);
13398 flush_sequence();
13400 trace("SetActiveWindow(hwnd), hwnd not visible\n");
13401 ret = SetActiveWindow(hwnd);
13402 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
13403 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
13404 flush_sequence();
13406 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
13407 ret = SetActiveWindow(popup);
13408 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
13409 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
13410 flush_sequence();
13412 trace("done\n");
13414 DestroyWindow(hwnd);
13417 static const struct message SetForegroundWindowSeq[] =
13419 { WM_NCACTIVATE, sent|wparam, 0 },
13420 { WM_GETTEXT, sent|defwinproc|optional },
13421 { WM_ACTIVATE, sent|wparam, 0 },
13422 { WM_ACTIVATEAPP, sent|wparam, 0 },
13423 { WM_KILLFOCUS, sent },
13424 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
13425 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
13426 { 0 }
13429 static void test_SetForegroundWindow(void)
13431 HWND hwnd;
13433 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
13434 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13435 100, 100, 200, 200, 0, 0, 0, NULL);
13436 ok (hwnd != 0, "Failed to create overlapped window\n");
13437 SetForegroundWindow( hwnd );
13438 flush_sequence();
13440 trace("SetForegroundWindow( 0 )\n");
13441 SetForegroundWindow( 0 );
13442 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
13443 trace("SetForegroundWindow( GetDesktopWindow() )\n");
13444 SetForegroundWindow( GetDesktopWindow() );
13445 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
13446 "foreground top level window", FALSE);
13447 trace("done\n");
13449 DestroyWindow(hwnd);
13452 static DWORD get_input_codepage( void )
13454 DWORD cp;
13455 int ret;
13456 HKL hkl = GetKeyboardLayout( 0 );
13458 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
13459 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
13460 if (!ret) cp = CP_ACP;
13461 return cp;
13464 static void test_dbcs_wm_char(void)
13466 BYTE dbch[2];
13467 WCHAR wch, bad_wch;
13468 HWND hwnd, hwnd2;
13469 MSG msg;
13470 DWORD time;
13471 POINT pt;
13472 DWORD_PTR res;
13473 CPINFOEXA cpinfo;
13474 UINT i, j, k;
13475 struct message wmCharSeq[2];
13476 BOOL ret;
13477 DWORD cp = get_input_codepage();
13479 if (!pGetCPInfoExA)
13481 win_skip("GetCPInfoExA is not available\n");
13482 return;
13485 pGetCPInfoExA( cp, 0, &cpinfo );
13486 if (cpinfo.MaxCharSize != 2)
13488 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
13489 return;
13492 dbch[0] = dbch[1] = 0;
13493 wch = 0;
13494 bad_wch = cpinfo.UnicodeDefaultChar;
13495 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
13496 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
13497 for (k = 128; k <= 255; k++)
13499 char str[2];
13500 WCHAR wstr[2];
13501 str[0] = j;
13502 str[1] = k;
13503 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
13504 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
13505 (BYTE)str[0] == j && (BYTE)str[1] == k &&
13506 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
13508 dbch[0] = j;
13509 dbch[1] = k;
13510 wch = wstr[0];
13511 break;
13515 if (!wch)
13517 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
13518 return;
13520 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
13521 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
13523 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
13524 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
13525 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
13526 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
13527 ok (hwnd != 0, "Failed to create overlapped window\n");
13528 ok (hwnd2 != 0, "Failed to create overlapped window\n");
13529 flush_sequence();
13531 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
13532 wmCharSeq[0].message = WM_CHAR;
13533 wmCharSeq[0].flags = sent|wparam;
13534 wmCharSeq[0].wParam = wch;
13536 /* posted message */
13537 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13538 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13539 ok( !ret, "got message %x\n", msg.message );
13540 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13541 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13542 ok( ret, "no message\n" );
13543 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13544 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
13545 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13546 ok( !ret, "got message %x\n", msg.message );
13548 /* posted thread message */
13549 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
13550 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13551 ok( !ret, "got message %x\n", msg.message );
13552 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13553 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13554 ok( ret, "no message\n" );
13555 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13556 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
13557 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13558 ok( !ret, "got message %x\n", msg.message );
13560 /* sent message */
13561 flush_sequence();
13562 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13563 ok_sequence( WmEmptySeq, "no messages", FALSE );
13564 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13565 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13566 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13567 ok( !ret, "got message %x\n", msg.message );
13569 /* sent message with timeout */
13570 flush_sequence();
13571 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
13572 ok_sequence( WmEmptySeq, "no messages", FALSE );
13573 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
13574 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13575 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13576 ok( !ret, "got message %x\n", msg.message );
13578 /* sent message with timeout and callback */
13579 flush_sequence();
13580 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
13581 ok_sequence( WmEmptySeq, "no messages", FALSE );
13582 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
13583 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13584 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13585 ok( !ret, "got message %x\n", msg.message );
13587 /* sent message with callback */
13588 flush_sequence();
13589 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13590 ok_sequence( WmEmptySeq, "no messages", FALSE );
13591 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
13592 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13593 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13594 ok( !ret, "got message %x\n", msg.message );
13596 /* direct window proc call */
13597 flush_sequence();
13598 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
13599 ok_sequence( WmEmptySeq, "no messages", FALSE );
13600 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
13601 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13603 /* dispatch message */
13604 msg.hwnd = hwnd;
13605 msg.message = WM_CHAR;
13606 msg.wParam = dbch[0];
13607 msg.lParam = 0;
13608 DispatchMessageA( &msg );
13609 ok_sequence( WmEmptySeq, "no messages", FALSE );
13610 msg.wParam = dbch[1];
13611 DispatchMessageA( &msg );
13612 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13614 /* window handle is irrelevant */
13615 flush_sequence();
13616 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
13617 ok_sequence( WmEmptySeq, "no messages", FALSE );
13618 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13619 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13620 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13621 ok( !ret, "got message %x\n", msg.message );
13623 /* interleaved post and send */
13624 flush_sequence();
13625 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
13626 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
13627 ok_sequence( WmEmptySeq, "no messages", FALSE );
13628 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13629 ok( !ret, "got message %x\n", msg.message );
13630 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13631 ok_sequence( WmEmptySeq, "no messages", FALSE );
13632 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13633 ok( ret, "no message\n" );
13634 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13635 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
13636 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13637 ok( !ret, "got message %x\n", msg.message );
13638 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13639 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13640 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13641 ok( !ret, "got message %x\n", msg.message );
13643 /* interleaved sent message and winproc */
13644 flush_sequence();
13645 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13646 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
13647 ok_sequence( WmEmptySeq, "no messages", FALSE );
13648 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13649 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13650 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
13651 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13653 /* interleaved winproc and dispatch */
13654 msg.hwnd = hwnd;
13655 msg.message = WM_CHAR;
13656 msg.wParam = dbch[0];
13657 msg.lParam = 0;
13658 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
13659 DispatchMessageA( &msg );
13660 ok_sequence( WmEmptySeq, "no messages", FALSE );
13661 msg.wParam = dbch[1];
13662 DispatchMessageA( &msg );
13663 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13664 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
13665 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13667 /* interleaved sends */
13668 flush_sequence();
13669 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13670 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
13671 ok_sequence( WmEmptySeq, "no messages", FALSE );
13672 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
13673 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13674 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13675 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13677 /* dbcs WM_CHAR */
13678 flush_sequence();
13679 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
13680 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13681 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13682 ok( !ret, "got message %x\n", msg.message );
13684 /* other char messages are not magic */
13685 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
13686 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13687 ok( ret, "no message\n" );
13688 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
13689 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
13690 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13691 ok( !ret, "got message %x\n", msg.message );
13692 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
13693 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13694 ok( ret, "no message\n" );
13695 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
13696 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
13697 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13698 ok( !ret, "got message %x\n", msg.message );
13700 /* test retrieving messages */
13702 PostMessageW( hwnd, WM_CHAR, wch, 0 );
13703 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13704 ok( ret, "no message\n" );
13705 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13706 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13707 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13708 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13709 ok( ret, "no message\n" );
13710 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13711 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13712 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13713 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13714 ok( !ret, "got message %x\n", msg.message );
13716 /* message filters */
13717 PostMessageW( hwnd, WM_CHAR, wch, 0 );
13718 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13719 ok( ret, "no message\n" );
13720 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13721 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13722 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13723 /* message id is filtered, hwnd is not */
13724 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
13725 ok( !ret, "no message\n" );
13726 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
13727 ok( ret, "no message\n" );
13728 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13729 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13730 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13731 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13732 ok( !ret, "got message %x\n", msg.message );
13734 /* mixing GetMessage and PostMessage */
13735 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
13736 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
13737 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13738 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13739 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13740 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
13741 time = msg.time;
13742 pt = msg.pt;
13743 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
13744 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13745 ok( ret, "no message\n" );
13746 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13747 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13748 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13749 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
13750 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
13751 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 );
13752 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13753 ok( !ret, "got message %x\n", msg.message );
13755 /* without PM_REMOVE */
13756 PostMessageW( hwnd, WM_CHAR, wch, 0 );
13757 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13758 ok( ret, "no message\n" );
13759 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13760 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13761 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13762 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13763 ok( ret, "no message\n" );
13764 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13765 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13766 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13767 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13768 ok( ret, "no message\n" );
13769 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13770 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13771 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13772 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13773 ok( ret, "no message\n" );
13774 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13775 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13776 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13777 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13778 ok( !ret, "got message %x\n", msg.message );
13780 DestroyWindow(hwnd);
13781 DestroyWindow(hwnd2);
13784 static void test_unicode_wm_char(void)
13786 HWND hwnd;
13787 MSG msg;
13788 struct message seq[2];
13789 HKL hkl_orig, hkl_greek;
13790 DWORD cp;
13791 LCID thread_locale;
13793 hkl_orig = GetKeyboardLayout( 0 );
13794 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
13795 if (cp != 1252)
13797 skip( "Default codepage %d\n", cp );
13798 return;
13801 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
13802 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
13804 skip( "Unable to load Greek keyboard layout\n" );
13805 return;
13808 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
13809 100, 100, 200, 200, 0, 0, 0, NULL );
13810 flush_sequence();
13812 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
13814 while (GetMessageW( &msg, hwnd, 0, 0 ))
13816 if (!ignore_message( msg.message )) break;
13819 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13820 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13821 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
13822 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
13824 DispatchMessageW( &msg );
13826 memset( seq, 0, sizeof(seq) );
13827 seq[0].message = WM_CHAR;
13828 seq[0].flags = sent|wparam;
13829 seq[0].wParam = 0x3b1;
13831 ok_sequence( seq, "unicode WM_CHAR", FALSE );
13833 flush_sequence();
13835 /* greek alpha -> 'a' in cp1252 */
13836 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
13838 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
13839 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13840 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13841 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
13842 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
13844 DispatchMessageA( &msg );
13846 seq[0].wParam = 0x61;
13847 ok_sequence( seq, "unicode WM_CHAR", FALSE );
13849 thread_locale = GetThreadLocale();
13850 ActivateKeyboardLayout( hkl_greek, 0 );
13851 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
13852 thread_locale, GetThreadLocale() );
13854 flush_sequence();
13856 /* greek alpha -> 0xe1 in cp1253 */
13857 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
13859 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
13860 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13861 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13862 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
13863 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
13865 DispatchMessageA( &msg );
13867 seq[0].wParam = 0x3b1;
13868 ok_sequence( seq, "unicode WM_CHAR", FALSE );
13870 DestroyWindow( hwnd );
13871 ActivateKeyboardLayout( hkl_orig, 0 );
13872 UnloadKeyboardLayout( hkl_greek );
13875 #define ID_LISTBOX 0x000f
13877 static const struct message wm_lb_setcursel_0[] =
13879 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
13880 { WM_CTLCOLORLISTBOX, sent|parent },
13881 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
13882 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13883 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13884 { 0 }
13886 static const struct message wm_lb_setcursel_1[] =
13888 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
13889 { WM_CTLCOLORLISTBOX, sent|parent },
13890 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
13891 { WM_CTLCOLORLISTBOX, sent|parent },
13892 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
13893 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
13894 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
13895 { 0 }
13897 static const struct message wm_lb_setcursel_2[] =
13899 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
13900 { WM_CTLCOLORLISTBOX, sent|parent },
13901 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
13902 { WM_CTLCOLORLISTBOX, sent|parent },
13903 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
13904 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
13905 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
13906 { 0 }
13908 static const struct message wm_lb_click_0[] =
13910 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
13911 { HCBT_SETFOCUS, hook },
13912 { WM_KILLFOCUS, sent|parent },
13913 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
13914 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13915 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13916 { WM_SETFOCUS, sent|defwinproc },
13918 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
13919 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
13920 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
13921 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
13922 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
13924 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
13925 { WM_CTLCOLORLISTBOX, sent|parent },
13926 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
13927 { WM_CTLCOLORLISTBOX, sent|parent },
13928 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
13929 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
13931 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13932 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13934 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
13935 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
13936 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
13937 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
13938 { 0 }
13940 static const struct message wm_lb_deletestring[] =
13942 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
13943 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
13944 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13945 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13946 { 0 }
13948 static const struct message wm_lb_deletestring_reset[] =
13950 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
13951 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
13952 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
13953 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13954 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13955 { 0 }
13958 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
13960 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
13962 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13964 static LONG defwndproc_counter = 0;
13965 LRESULT ret;
13966 struct recvd_message msg;
13968 /* do not log painting messages */
13969 if (message != WM_PAINT &&
13970 message != WM_NCPAINT &&
13971 message != WM_SYNCPAINT &&
13972 message != WM_ERASEBKGND &&
13973 message != WM_NCHITTEST &&
13974 message != WM_GETTEXT &&
13975 !ignore_message( message ))
13977 msg.hwnd = hwnd;
13978 msg.message = message;
13979 msg.flags = sent|wparam|lparam;
13980 if (defwndproc_counter) msg.flags |= defwinproc;
13981 msg.wParam = wp;
13982 msg.lParam = lp;
13983 msg.descr = "listbox";
13984 add_message(&msg);
13987 defwndproc_counter++;
13988 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
13989 defwndproc_counter--;
13991 return ret;
13994 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
13995 int caret_index, int top_index, int line)
13997 LRESULT ret;
13999 /* calling an orig proc helps to avoid unnecessary message logging */
14000 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14001 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14002 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14003 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14004 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14005 ok_(__FILE__, line)(ret == caret_index ||
14006 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
14007 "expected caret index %d, got %ld\n", caret_index, ret);
14008 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14009 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14012 static void test_listbox_messages(void)
14014 HWND parent, listbox;
14015 LRESULT ret;
14017 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14018 100, 100, 200, 200, 0, 0, 0, NULL);
14019 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14020 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14021 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14022 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14024 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14026 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14027 ok(ret == 0, "expected 0, got %ld\n", ret);
14028 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14029 ok(ret == 1, "expected 1, got %ld\n", ret);
14030 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14031 ok(ret == 2, "expected 2, got %ld\n", ret);
14033 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14035 flush_sequence();
14037 log_all_parent_messages++;
14039 trace("selecting item 0\n");
14040 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14041 ok(ret == 0, "expected 0, got %ld\n", ret);
14042 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14043 check_lb_state(listbox, 3, 0, 0, 0);
14044 flush_sequence();
14046 trace("selecting item 1\n");
14047 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14048 ok(ret == 1, "expected 1, got %ld\n", ret);
14049 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14050 check_lb_state(listbox, 3, 1, 1, 0);
14052 trace("selecting item 2\n");
14053 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14054 ok(ret == 2, "expected 2, got %ld\n", ret);
14055 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14056 check_lb_state(listbox, 3, 2, 2, 0);
14058 trace("clicking on item 0\n");
14059 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14060 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14061 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14062 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14063 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14064 check_lb_state(listbox, 3, 0, 0, 0);
14065 flush_sequence();
14067 trace("deleting item 0\n");
14068 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14069 ok(ret == 2, "expected 2, got %ld\n", ret);
14070 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14071 check_lb_state(listbox, 2, -1, 0, 0);
14072 flush_sequence();
14074 trace("deleting item 0\n");
14075 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14076 ok(ret == 1, "expected 1, got %ld\n", ret);
14077 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14078 check_lb_state(listbox, 1, -1, 0, 0);
14079 flush_sequence();
14081 trace("deleting item 0\n");
14082 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14083 ok(ret == 0, "expected 0, got %ld\n", ret);
14084 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14085 check_lb_state(listbox, 0, -1, 0, 0);
14086 flush_sequence();
14088 trace("deleting item 0\n");
14089 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14090 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14091 check_lb_state(listbox, 0, -1, 0, 0);
14092 flush_sequence();
14094 log_all_parent_messages--;
14096 DestroyWindow(listbox);
14097 DestroyWindow(parent);
14100 /*************************** Menu test ******************************/
14101 static const struct message wm_popup_menu_1[] =
14103 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14104 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14105 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
14106 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
14107 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
14108 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
14109 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14110 { WM_INITMENU, sent|lparam, 0, 0 },
14111 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
14112 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
14113 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
14114 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
14115 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
14116 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14117 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
14118 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
14119 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14120 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14121 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14122 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
14123 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14124 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14125 { 0 }
14127 static const struct message wm_popup_menu_2[] =
14129 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14130 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14131 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14132 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14133 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14134 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14135 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14136 { WM_INITMENU, sent|lparam, 0, 0 },
14137 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14138 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14139 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14140 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14141 { HCBT_CREATEWND, hook },
14142 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14143 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14144 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14145 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14146 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14147 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14148 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14149 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14150 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14151 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14152 { HCBT_DESTROYWND, hook },
14153 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14154 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14155 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14156 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14157 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14158 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
14159 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14160 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14161 { 0 }
14163 static const struct message wm_popup_menu_3[] =
14165 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14166 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14167 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14168 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14169 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14170 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14171 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14172 { WM_INITMENU, sent|lparam, 0, 0 },
14173 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14174 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14175 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14176 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14177 { HCBT_CREATEWND, hook },
14178 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14179 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14180 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14181 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14182 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14183 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14184 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14185 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14186 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14187 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14188 { HCBT_DESTROYWND, hook },
14189 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14190 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14191 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14192 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14193 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14194 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
14195 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14196 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14197 { 0 }
14200 static const struct message wm_single_menu_item[] =
14202 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14203 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14204 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
14205 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
14206 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
14207 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
14208 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14209 { WM_INITMENU, sent|lparam, 0, 0 },
14210 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
14211 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14212 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14213 { WM_MENUCOMMAND, sent },
14214 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
14215 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
14216 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
14217 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
14219 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
14220 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
14221 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
14222 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
14223 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
14224 { 0 }
14227 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14229 if (message == WM_ENTERIDLE ||
14230 message == WM_INITMENU ||
14231 message == WM_INITMENUPOPUP ||
14232 message == WM_MENUSELECT ||
14233 message == WM_PARENTNOTIFY ||
14234 message == WM_ENTERMENULOOP ||
14235 message == WM_EXITMENULOOP ||
14236 message == WM_UNINITMENUPOPUP ||
14237 message == WM_KEYDOWN ||
14238 message == WM_KEYUP ||
14239 message == WM_CHAR ||
14240 message == WM_SYSKEYDOWN ||
14241 message == WM_SYSKEYUP ||
14242 message == WM_SYSCHAR ||
14243 message == WM_COMMAND ||
14244 message == WM_MENUCOMMAND)
14246 struct recvd_message msg;
14248 msg.hwnd = hwnd;
14249 msg.message = message;
14250 msg.flags = sent|wparam|lparam;
14251 msg.wParam = wp;
14252 msg.lParam = lp;
14253 msg.descr = "parent_menu_proc";
14254 add_message(&msg);
14257 return DefWindowProcA(hwnd, message, wp, lp);
14260 static void set_menu_style(HMENU hmenu, DWORD style)
14262 MENUINFO mi;
14263 BOOL ret;
14265 mi.cbSize = sizeof(mi);
14266 mi.fMask = MIM_STYLE;
14267 mi.dwStyle = style;
14268 SetLastError(0xdeadbeef);
14269 ret = pSetMenuInfo(hmenu, &mi);
14270 ok(ret, "SetMenuInfo error %u\n", GetLastError());
14273 static DWORD get_menu_style(HMENU hmenu)
14275 MENUINFO mi;
14276 BOOL ret;
14278 mi.cbSize = sizeof(mi);
14279 mi.fMask = MIM_STYLE;
14280 mi.dwStyle = 0;
14281 SetLastError(0xdeadbeef);
14282 ret = pGetMenuInfo(hmenu, &mi);
14283 ok(ret, "GetMenuInfo error %u\n", GetLastError());
14285 return mi.dwStyle;
14288 static void test_menu_messages(void)
14290 MSG msg;
14291 WNDCLASSA cls;
14292 HMENU hmenu, hmenu_popup;
14293 HWND hwnd;
14294 DWORD style;
14296 if (!pGetMenuInfo || !pSetMenuInfo)
14298 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
14299 return;
14301 cls.style = 0;
14302 cls.lpfnWndProc = parent_menu_proc;
14303 cls.cbClsExtra = 0;
14304 cls.cbWndExtra = 0;
14305 cls.hInstance = GetModuleHandleA(0);
14306 cls.hIcon = 0;
14307 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
14308 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
14309 cls.lpszMenuName = NULL;
14310 cls.lpszClassName = "TestMenuClass";
14311 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14312 if (!RegisterClassA(&cls)) assert(0);
14314 SetLastError(0xdeadbeef);
14315 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14316 100, 100, 200, 200, 0, 0, 0, NULL);
14317 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
14319 SetLastError(0xdeadbeef);
14320 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
14321 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
14323 SetMenu(hwnd, hmenu);
14324 SetForegroundWindow( hwnd );
14325 flush_events();
14327 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
14328 style = get_menu_style(hmenu);
14329 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14331 hmenu_popup = GetSubMenu(hmenu, 0);
14332 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14333 style = get_menu_style(hmenu_popup);
14334 ok(style == 0, "expected 0, got %u\n", style);
14336 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14337 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14338 style = get_menu_style(hmenu_popup);
14339 ok(style == 0, "expected 0, got %u\n", style);
14341 /* Alt+E, Enter */
14342 trace("testing a popup menu command\n");
14343 flush_sequence();
14344 keybd_event(VK_MENU, 0, 0, 0);
14345 keybd_event('E', 0, 0, 0);
14346 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
14347 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14348 keybd_event(VK_RETURN, 0, 0, 0);
14349 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14350 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14352 TranslateMessage(&msg);
14353 DispatchMessageA(&msg);
14355 if (!sequence_cnt) /* we didn't get any message */
14357 skip( "queuing key events not supported\n" );
14358 goto done;
14360 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
14361 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
14363 win_skip( "menu tracking through VK_MENU not supported\n" );
14364 goto done;
14366 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
14368 /* Alt+F, Right, Enter */
14369 trace("testing submenu of a popup menu command\n");
14370 flush_sequence();
14371 keybd_event(VK_MENU, 0, 0, 0);
14372 keybd_event('F', 0, 0, 0);
14373 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
14374 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14375 keybd_event(VK_RIGHT, 0, 0, 0);
14376 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
14377 keybd_event(VK_RETURN, 0, 0, 0);
14378 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14379 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14381 TranslateMessage(&msg);
14382 DispatchMessageA(&msg);
14384 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
14386 trace("testing single menu item command\n");
14387 flush_sequence();
14388 keybd_event(VK_MENU, 0, 0, 0);
14389 keybd_event('Q', 0, 0, 0);
14390 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
14391 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14392 keybd_event(VK_ESCAPE, 0, 0, 0);
14393 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
14394 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14396 TranslateMessage(&msg);
14397 DispatchMessageA(&msg);
14399 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
14401 set_menu_style(hmenu, 0);
14402 style = get_menu_style(hmenu);
14403 ok(style == 0, "expected 0, got %u\n", style);
14405 hmenu_popup = GetSubMenu(hmenu, 0);
14406 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14407 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
14408 style = get_menu_style(hmenu_popup);
14409 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14411 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14412 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14413 style = get_menu_style(hmenu_popup);
14414 ok(style == 0, "expected 0, got %u\n", style);
14416 /* Alt+F, Right, Enter */
14417 trace("testing submenu of a popup menu command\n");
14418 flush_sequence();
14419 keybd_event(VK_MENU, 0, 0, 0);
14420 keybd_event('F', 0, 0, 0);
14421 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
14422 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14423 keybd_event(VK_RIGHT, 0, 0, 0);
14424 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
14425 keybd_event(VK_RETURN, 0, 0, 0);
14426 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14427 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14429 TranslateMessage(&msg);
14430 DispatchMessageA(&msg);
14432 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
14434 done:
14435 DestroyWindow(hwnd);
14436 DestroyMenu(hmenu);
14440 static void test_paintingloop(void)
14442 HWND hwnd;
14444 paint_loop_done = FALSE;
14445 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
14446 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
14447 100, 100, 100, 100, 0, 0, 0, NULL );
14448 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
14449 ShowWindow(hwnd,SW_NORMAL);
14450 SetFocus(hwnd);
14452 while (!paint_loop_done)
14454 MSG msg;
14455 if (PeekMessageA(&msg, 0, 0, 0, 1))
14457 TranslateMessage(&msg);
14458 DispatchMessageA(&msg);
14461 DestroyWindow(hwnd);
14464 static const struct message NCRBUTTONDOWNSeq[] =
14466 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14467 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14468 { WM_CAPTURECHANGED, sent },
14469 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
14470 { 0 }
14473 static const struct message NCXBUTTONUPSeq1[] =
14475 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
14476 { 0 }
14479 static const struct message NCXBUTTONUPSeq2[] =
14481 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
14482 { 0 }
14485 struct rbuttonup_thread_data
14487 HWND hwnd;
14488 HANDLE wndproc_finished;
14491 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
14493 struct rbuttonup_thread_data *data = arg;
14494 DWORD ret;
14496 ret = WaitForSingleObject( data->wndproc_finished, 500 );
14497 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
14498 if( ret == WAIT_OBJECT_0 ) return 0;
14500 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
14501 return 0;
14504 static void test_defwinproc(void)
14506 HWND hwnd;
14507 MSG msg;
14508 BOOL gotwmquit = FALSE;
14509 POINT pos;
14510 RECT rect;
14511 INT x, y;
14512 LRESULT res;
14513 struct rbuttonup_thread_data data;
14514 char buffA[64];
14515 HANDLE thread;
14517 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
14518 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
14519 assert(hwnd);
14520 flush_events();
14522 buffA[0] = 0;
14523 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
14524 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
14526 /* Zero high word of the lParam */
14527 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
14528 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
14530 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
14531 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
14533 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
14534 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
14536 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
14537 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
14539 GetCursorPos(&pos);
14540 GetWindowRect(hwnd, &rect);
14541 x = (rect.left+rect.right) / 2;
14542 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
14543 SetCursorPos(x, y);
14544 flush_events();
14545 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
14546 ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
14548 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
14549 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
14550 flush_events();
14552 flush_sequence();
14553 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
14554 /* workaround for missing support for clicking on window frame */
14555 data.hwnd = hwnd;
14556 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
14557 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
14559 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
14560 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
14562 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
14563 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
14564 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
14566 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
14567 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
14568 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
14570 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
14571 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
14572 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
14574 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
14575 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
14576 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
14578 SetEvent( data.wndproc_finished );
14579 WaitForSingleObject( thread, 1000 );
14580 CloseHandle( data.wndproc_finished );
14581 CloseHandle( thread );
14583 SetCursorPos(pos.x, pos.y);
14585 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
14586 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
14587 if( msg.message == WM_QUIT) gotwmquit = TRUE;
14588 DispatchMessageA( &msg );
14590 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
14591 DestroyWindow( hwnd);
14594 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
14595 static void clear_clipboard_(int line, HWND hWnd)
14597 BOOL succ;
14598 succ = OpenClipboard(hWnd);
14599 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
14600 succ = EmptyClipboard();
14601 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
14602 succ = CloseClipboard();
14603 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
14606 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
14607 static void expect_HWND_(int line, HWND expected, HWND got)
14609 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
14612 static WNDPROC pOldViewerProc;
14614 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
14616 static BOOL recursion_guard;
14618 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
14620 recursion_guard = TRUE;
14621 clear_clipboard(hWnd);
14622 recursion_guard = FALSE;
14624 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
14627 static void test_clipboard_viewers(void)
14629 static struct message wm_change_cb_chain[] =
14631 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
14632 { 0 }
14634 static const struct message wm_clipboard_destroyed[] =
14636 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
14637 { 0 }
14639 static struct message wm_clipboard_changed[] =
14641 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
14642 { 0 }
14644 static struct message wm_clipboard_changed_and_owned[] =
14646 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
14647 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
14648 { 0 }
14651 HINSTANCE hInst = GetModuleHandleA(NULL);
14652 HWND hWnd1, hWnd2, hWnd3;
14653 HWND hOrigViewer;
14654 HWND hRet;
14656 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
14657 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
14658 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
14659 GetDesktopWindow(), NULL, hInst, NULL);
14660 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
14661 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
14662 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
14663 GetDesktopWindow(), NULL, hInst, NULL);
14664 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
14665 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
14666 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
14667 GetDesktopWindow(), NULL, hInst, NULL);
14668 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
14669 assert(hWnd1 && hWnd2 && hWnd3);
14671 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
14672 flush_sequence();
14674 /* Test getting the clipboard viewer and setting the viewer to NULL. */
14675 hOrigViewer = GetClipboardViewer();
14676 hRet = SetClipboardViewer(NULL);
14677 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
14678 expect_HWND(hOrigViewer, hRet);
14679 expect_HWND(NULL, GetClipboardViewer());
14681 /* Test registering hWnd1 as a viewer. */
14682 hRet = SetClipboardViewer(hWnd1);
14683 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
14684 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
14685 expect_HWND(NULL, hRet);
14686 expect_HWND(hWnd1, GetClipboardViewer());
14688 /* Test that changing the clipboard actually refreshes the registered viewer. */
14689 clear_clipboard(hWnd1);
14690 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
14691 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
14693 /* Again, but with different owner. */
14694 clear_clipboard(hWnd2);
14695 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
14696 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
14698 /* Test re-registering same window. */
14699 hRet = SetClipboardViewer(hWnd1);
14700 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
14701 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
14702 expect_HWND(hWnd1, hRet);
14703 expect_HWND(hWnd1, GetClipboardViewer());
14705 /* Test ChangeClipboardChain. */
14706 ChangeClipboardChain(hWnd2, hWnd3);
14707 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
14708 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
14709 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
14710 expect_HWND(hWnd1, GetClipboardViewer());
14712 ChangeClipboardChain(hWnd2, NULL);
14713 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
14714 wm_change_cb_chain[0].lParam = 0;
14715 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
14716 expect_HWND(hWnd1, GetClipboardViewer());
14718 ChangeClipboardChain(NULL, hWnd2);
14719 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
14720 expect_HWND(hWnd1, GetClipboardViewer());
14722 /* Actually change clipboard viewer with ChangeClipboardChain. */
14723 ChangeClipboardChain(hWnd1, hWnd2);
14724 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
14725 expect_HWND(hWnd2, GetClipboardViewer());
14727 /* Test that no refresh messages are sent when viewer has unregistered. */
14728 clear_clipboard(hWnd2);
14729 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
14731 /* Register hWnd1 again. */
14732 ChangeClipboardChain(hWnd2, hWnd1);
14733 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
14734 expect_HWND(hWnd1, GetClipboardViewer());
14736 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
14737 * changes the clipboard. When this happens, the system shouldn't send
14738 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
14740 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
14741 clear_clipboard(hWnd2);
14742 /* The clipboard owner is changed in recursive_viewer_proc: */
14743 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
14744 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
14746 /* Test unregistering. */
14747 ChangeClipboardChain(hWnd1, NULL);
14748 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
14749 expect_HWND(NULL, GetClipboardViewer());
14751 clear_clipboard(hWnd1);
14752 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
14754 DestroyWindow(hWnd1);
14755 DestroyWindow(hWnd2);
14756 DestroyWindow(hWnd3);
14757 SetClipboardViewer(hOrigViewer);
14760 static void test_PostMessage(void)
14762 static const struct
14764 HWND hwnd;
14765 BOOL ret;
14766 } data[] =
14768 { HWND_TOP /* 0 */, TRUE },
14769 { HWND_BROADCAST, TRUE },
14770 { HWND_BOTTOM, TRUE },
14771 { HWND_TOPMOST, TRUE },
14772 { HWND_NOTOPMOST, FALSE },
14773 { HWND_MESSAGE, FALSE },
14774 { (HWND)0xdeadbeef, FALSE }
14776 int i;
14777 HWND hwnd;
14778 BOOL ret;
14779 MSG msg;
14780 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
14782 SetLastError(0xdeadbeef);
14783 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
14784 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
14786 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
14787 return;
14789 assert(hwnd);
14791 flush_events();
14793 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
14794 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
14796 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
14798 memset(&msg, 0xab, sizeof(msg));
14799 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
14800 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
14801 if (data[i].ret)
14803 if (data[i].hwnd)
14804 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
14805 msg.wParam == 0x5678 && msg.lParam == 0x1234,
14806 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
14807 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
14808 else
14809 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
14810 msg.wParam == 0x1234 && msg.lParam == 0x5678,
14811 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
14812 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
14816 DestroyWindow(hwnd);
14817 flush_events();
14820 static LPARAM g_broadcast_lparam;
14821 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14823 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
14825 if (wParam == 0xbaadbeef)
14826 g_broadcast_lparam = wParam;
14827 else
14828 g_broadcast_lparam = 0;
14830 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
14833 static void test_broadcast(void)
14835 static const UINT messages[] =
14837 WM_USER-1,
14838 WM_USER,
14839 WM_USER+1,
14840 0xc000-1,
14841 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
14842 0xffff,
14844 WNDPROC oldproc;
14845 unsigned int i;
14846 HWND hwnd;
14848 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
14849 ok(hwnd != NULL, "got %p\n", hwnd);
14851 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
14852 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
14854 for (i = 0; i < sizeof(messages)/sizeof(messages[0]); i++)
14856 BOOL ret;
14857 MSG msg;
14859 flush_events();
14860 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14863 /* post, broadcast */
14864 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
14865 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
14867 memset(&msg, 0xab, sizeof(msg));
14868 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14869 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14871 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
14872 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
14874 else
14876 ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
14879 /* post, topmost */
14880 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
14881 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
14883 memset(&msg, 0xab, sizeof(msg));
14884 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14885 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14887 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
14888 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
14890 else
14892 ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
14895 /* send, broadcast */
14896 g_broadcast_lparam = 0xdead;
14897 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
14898 if (!ret && GetLastError() == ERROR_TIMEOUT)
14899 win_skip("broadcasting test %d, timeout\n", i);
14900 else
14902 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14904 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14905 g_broadcast_lparam, GetLastError());
14907 else
14909 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14910 g_broadcast_lparam, GetLastError());
14914 /* send, topmost */
14915 g_broadcast_lparam = 0xdead;
14916 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
14917 if (!ret && GetLastError() == ERROR_TIMEOUT)
14918 win_skip("broadcasting test %d, timeout\n", i);
14919 else
14921 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14923 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14924 g_broadcast_lparam, GetLastError());
14926 else
14928 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14929 g_broadcast_lparam, GetLastError());
14934 DestroyWindow(hwnd);
14937 static const struct
14939 DWORD exp, broken;
14940 BOOL todo;
14941 } wait_idle_expect[] =
14943 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14944 { WAIT_TIMEOUT, 0, FALSE },
14945 { WAIT_TIMEOUT, 0, FALSE },
14946 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14947 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14948 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
14949 { WAIT_TIMEOUT, 0, FALSE },
14950 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14951 { 0, 0, FALSE },
14952 { 0, 0, FALSE },
14953 /* 10 */ { 0, 0, FALSE },
14954 { 0, 0, FALSE },
14955 { 0, WAIT_TIMEOUT, FALSE },
14956 { 0, 0, FALSE },
14957 { 0, 0, FALSE },
14958 /* 15 */ { 0, 0, FALSE },
14959 { WAIT_TIMEOUT, 0, FALSE },
14960 { WAIT_TIMEOUT, 0, FALSE },
14961 { WAIT_TIMEOUT, 0, FALSE },
14962 { WAIT_TIMEOUT, 0, FALSE },
14963 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
14966 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
14968 MSG msg;
14970 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14971 Sleep( 200 );
14972 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
14973 return 0;
14976 static void do_wait_idle_child( int arg )
14978 WNDCLASSA cls;
14979 MSG msg;
14980 HWND hwnd = 0;
14981 HANDLE thread;
14982 DWORD id;
14983 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
14984 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
14986 memset( &cls, 0, sizeof(cls) );
14987 cls.lpfnWndProc = DefWindowProcA;
14988 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
14989 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
14990 cls.lpszClassName = "TestClass";
14991 RegisterClassA( &cls );
14993 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
14995 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
14996 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
14998 switch (arg)
15000 case 0:
15001 SetEvent( start_event );
15002 break;
15003 case 1:
15004 SetEvent( start_event );
15005 Sleep( 200 );
15006 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15007 break;
15008 case 2:
15009 SetEvent( start_event );
15010 Sleep( 200 );
15011 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15012 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
15013 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15014 break;
15015 case 3:
15016 SetEvent( start_event );
15017 Sleep( 200 );
15018 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
15019 break;
15020 case 4:
15021 SetEvent( start_event );
15022 Sleep( 200 );
15023 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15024 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15025 break;
15026 case 5:
15027 SetEvent( start_event );
15028 Sleep( 200 );
15029 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15030 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15031 break;
15032 case 6:
15033 SetEvent( start_event );
15034 Sleep( 200 );
15035 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15036 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
15038 GetMessageA( &msg, 0, 0, 0 );
15039 DispatchMessageA( &msg );
15041 break;
15042 case 7:
15043 SetEvent( start_event );
15044 Sleep( 200 );
15045 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15046 SetTimer( hwnd, 3, 1, NULL );
15047 Sleep( 200 );
15048 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15049 break;
15050 case 8:
15051 SetEvent( start_event );
15052 Sleep( 200 );
15053 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15054 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15055 break;
15056 case 9:
15057 SetEvent( start_event );
15058 Sleep( 200 );
15059 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15060 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15061 for (;;) GetMessageA( &msg, 0, 0, 0 );
15062 break;
15063 case 10:
15064 SetEvent( start_event );
15065 Sleep( 200 );
15066 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15067 SetTimer( hwnd, 3, 1, NULL );
15068 Sleep( 200 );
15069 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15070 break;
15071 case 11:
15072 SetEvent( start_event );
15073 Sleep( 200 );
15074 return; /* exiting the process makes WaitForInputIdle return success too */
15075 case 12:
15076 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15077 Sleep( 200 );
15078 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15079 SetEvent( start_event );
15080 break;
15081 case 13:
15082 SetEvent( start_event );
15083 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15084 Sleep( 200 );
15085 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
15086 WaitForSingleObject( thread, 10000 );
15087 CloseHandle( thread );
15088 break;
15089 case 14:
15090 SetEvent( start_event );
15091 Sleep( 200 );
15092 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
15093 break;
15094 case 15:
15095 SetEvent( start_event );
15096 Sleep( 200 );
15097 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
15098 break;
15099 case 16:
15100 SetEvent( start_event );
15101 Sleep( 200 );
15102 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
15103 break;
15104 case 17:
15105 SetEvent( start_event );
15106 Sleep( 200 );
15107 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
15108 break;
15109 case 18:
15110 SetEvent( start_event );
15111 Sleep( 200 );
15112 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
15113 break;
15114 case 19:
15115 SetEvent( start_event );
15116 Sleep( 200 );
15117 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
15118 break;
15119 case 20:
15120 SetEvent( start_event );
15121 Sleep( 200 );
15122 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
15123 break;
15125 WaitForSingleObject( end_event, 2000 );
15126 CloseHandle( start_event );
15127 CloseHandle( end_event );
15128 if (hwnd) DestroyWindow( hwnd );
15131 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
15133 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
15134 return DefWindowProcA( hwnd, msg, wp, lp );
15137 static DWORD CALLBACK wait_idle_thread( void *arg )
15139 WNDCLASSA cls;
15140 MSG msg;
15141 HWND hwnd;
15143 memset( &cls, 0, sizeof(cls) );
15144 cls.lpfnWndProc = wait_idle_proc;
15145 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15146 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15147 cls.lpszClassName = "TestClass";
15148 RegisterClassA( &cls );
15150 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
15151 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
15152 DestroyWindow(hwnd);
15153 return 0;
15156 static void test_WaitForInputIdle( char *argv0 )
15158 char path[MAX_PATH];
15159 PROCESS_INFORMATION pi;
15160 STARTUPINFOA startup;
15161 BOOL ret;
15162 HANDLE start_event, end_event, thread;
15163 unsigned int i;
15164 DWORD id;
15165 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
15166 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
15167 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
15169 if (console_app) /* build the test with -mwindows for better coverage */
15170 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
15172 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
15173 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
15174 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
15175 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
15177 memset( &startup, 0, sizeof(startup) );
15178 startup.cb = sizeof(startup);
15179 startup.dwFlags = STARTF_USESHOWWINDOW;
15180 startup.wShowWindow = SW_SHOWNORMAL;
15182 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
15184 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
15186 ResetEvent( start_event );
15187 ResetEvent( end_event );
15188 sprintf( path, "%s msg %u", argv0, i );
15189 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
15190 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
15191 if (ret)
15193 ret = WaitForSingleObject( start_event, 5000 );
15194 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
15195 if (ret == WAIT_OBJECT_0)
15197 ret = WaitForInputIdle( pi.hProcess, 1000 );
15198 if (ret == WAIT_FAILED)
15199 ok( console_app ||
15200 ret == wait_idle_expect[i].exp ||
15201 broken(ret == wait_idle_expect[i].broken),
15202 "%u: WaitForInputIdle error %08x expected %08x\n",
15203 i, ret, wait_idle_expect[i].exp );
15204 else todo_wine_if (wait_idle_expect[i].todo)
15205 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
15206 "%u: WaitForInputIdle error %08x expected %08x\n",
15207 i, ret, wait_idle_expect[i].exp );
15208 SetEvent( end_event );
15209 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
15211 TerminateProcess( pi.hProcess, 0 ); /* just in case */
15212 winetest_wait_child_process( pi.hProcess );
15213 ret = WaitForInputIdle( pi.hProcess, 100 );
15214 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
15215 CloseHandle( pi.hProcess );
15216 CloseHandle( pi.hThread );
15219 CloseHandle( start_event );
15220 PostThreadMessageA( id, WM_QUIT, 0, 0 );
15221 WaitForSingleObject( thread, 10000 );
15222 CloseHandle( thread );
15225 static const struct message WmSetParentSeq_1[] = {
15226 { WM_SHOWWINDOW, sent|wparam, 0 },
15227 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15228 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15229 { WM_CHILDACTIVATE, sent },
15230 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
15231 { WM_MOVE, sent|defwinproc|wparam, 0 },
15232 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15233 { WM_SHOWWINDOW, sent|wparam, 1 },
15234 { 0 }
15237 static const struct message WmSetParentSeq_2[] = {
15238 { WM_SHOWWINDOW, sent|wparam, 0 },
15239 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15240 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15241 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15242 { HCBT_SETFOCUS, hook|optional },
15243 { WM_NCACTIVATE, sent|wparam|optional, 0 },
15244 { WM_ACTIVATE, sent|wparam|optional, 0 },
15245 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15246 { WM_KILLFOCUS, sent|wparam, 0 },
15247 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15248 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15249 { HCBT_ACTIVATE, hook|optional },
15250 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
15251 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15252 { WM_NCACTIVATE, sent|wparam|optional, 1 },
15253 { WM_ACTIVATE, sent|wparam|optional, 1 },
15254 { HCBT_SETFOCUS, hook|optional },
15255 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15256 { WM_SETFOCUS, sent|optional|defwinproc },
15257 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
15258 { WM_MOVE, sent|defwinproc|wparam, 0 },
15259 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15260 { WM_SHOWWINDOW, sent|wparam, 1 },
15261 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15262 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15263 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15264 { 0 }
15268 static void test_SetParent(void)
15270 HWND parent1, parent2, child, popup;
15271 RECT rc, rc_old;
15273 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15274 100, 100, 200, 200, 0, 0, 0, NULL);
15275 ok(parent1 != 0, "Failed to create parent1 window\n");
15277 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15278 400, 100, 200, 200, 0, 0, 0, NULL);
15279 ok(parent2 != 0, "Failed to create parent2 window\n");
15281 /* WS_CHILD window */
15282 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
15283 10, 10, 150, 150, parent1, 0, 0, NULL);
15284 ok(child != 0, "Failed to create child window\n");
15286 GetWindowRect(parent1, &rc);
15287 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
15288 GetWindowRect(child, &rc_old);
15289 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
15290 trace("child %s\n", wine_dbgstr_rect(&rc_old));
15292 flush_sequence();
15294 SetParent(child, parent2);
15295 flush_events();
15296 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
15298 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15299 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
15301 GetWindowRect(parent2, &rc);
15302 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15303 GetWindowRect(child, &rc);
15304 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
15305 trace("child %s\n", wine_dbgstr_rect(&rc));
15307 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15308 wine_dbgstr_rect(&rc));
15310 /* WS_POPUP window */
15311 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
15312 20, 20, 100, 100, 0, 0, 0, NULL);
15313 ok(popup != 0, "Failed to create popup window\n");
15315 GetWindowRect(popup, &rc_old);
15316 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
15318 flush_sequence();
15320 SetParent(popup, child);
15321 flush_events();
15322 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
15324 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15325 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
15327 GetWindowRect(child, &rc);
15328 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15329 GetWindowRect(popup, &rc);
15330 MapWindowPoints(0, child, (POINT *)&rc, 2);
15331 trace("popup %s\n", wine_dbgstr_rect(&rc));
15333 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15334 wine_dbgstr_rect(&rc));
15336 DestroyWindow(popup);
15337 DestroyWindow(child);
15338 DestroyWindow(parent1);
15339 DestroyWindow(parent2);
15341 flush_sequence();
15344 static const struct message WmKeyReleaseOnly[] = {
15345 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
15346 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
15347 { 0 }
15349 static const struct message WmKeyPressNormal[] = {
15350 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
15351 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
15352 { 0 }
15354 static const struct message WmKeyPressRepeat[] = {
15355 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
15356 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
15357 { 0 }
15359 static const struct message WmKeyReleaseNormal[] = {
15360 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
15361 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
15362 { 0 }
15365 static void test_keyflags(void)
15367 HWND test_window;
15368 SHORT key_state;
15369 BYTE keyboard_state[256];
15370 MSG msg;
15372 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15373 100, 100, 200, 200, 0, 0, 0, NULL);
15375 flush_events();
15376 flush_sequence();
15378 /* keyup without a keydown */
15379 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15380 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15381 DispatchMessageA(&msg);
15382 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
15384 key_state = GetAsyncKeyState(0x41);
15385 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15387 key_state = GetKeyState(0x41);
15388 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15390 /* keydown */
15391 keybd_event(0x41, 0, 0, 0);
15392 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15393 DispatchMessageA(&msg);
15394 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
15396 key_state = GetAsyncKeyState(0x41);
15397 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15399 key_state = GetKeyState(0x41);
15400 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15402 /* keydown repeat */
15403 keybd_event(0x41, 0, 0, 0);
15404 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15405 DispatchMessageA(&msg);
15406 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
15408 key_state = GetAsyncKeyState(0x41);
15409 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15411 key_state = GetKeyState(0x41);
15412 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15414 /* keyup */
15415 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15416 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15417 DispatchMessageA(&msg);
15418 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
15420 key_state = GetAsyncKeyState(0x41);
15421 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15423 key_state = GetKeyState(0x41);
15424 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15426 /* set the key state in this thread */
15427 GetKeyboardState(keyboard_state);
15428 keyboard_state[0x41] = 0x80;
15429 SetKeyboardState(keyboard_state);
15431 key_state = GetAsyncKeyState(0x41);
15432 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15434 /* keydown */
15435 keybd_event(0x41, 0, 0, 0);
15436 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15437 DispatchMessageA(&msg);
15438 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
15440 key_state = GetAsyncKeyState(0x41);
15441 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15443 key_state = GetKeyState(0x41);
15444 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15446 /* clear the key state in this thread */
15447 GetKeyboardState(keyboard_state);
15448 keyboard_state[0x41] = 0;
15449 SetKeyboardState(keyboard_state);
15451 key_state = GetAsyncKeyState(0x41);
15452 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15454 /* keyup */
15455 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15456 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15457 DispatchMessageA(&msg);
15458 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
15460 key_state = GetAsyncKeyState(0x41);
15461 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15463 key_state = GetKeyState(0x41);
15464 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15466 DestroyWindow(test_window);
15467 flush_sequence();
15470 static const struct message WmHotkeyPressLWIN[] = {
15471 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
15472 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
15473 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
15474 { 0 }
15476 static const struct message WmHotkeyPress[] = {
15477 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15478 { WM_HOTKEY, sent|wparam, 5 },
15479 { 0 }
15481 static const struct message WmHotkeyRelease[] = {
15482 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15483 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
15484 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
15485 { 0 }
15487 static const struct message WmHotkeyReleaseLWIN[] = {
15488 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
15489 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
15490 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
15491 { 0 }
15493 static const struct message WmHotkeyCombined[] = {
15494 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
15495 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15496 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15497 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
15498 { WM_APP, sent, 0, 0 },
15499 { WM_HOTKEY, sent|wparam, 5 },
15500 { WM_APP+1, sent, 0, 0 },
15501 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
15502 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
15503 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
15504 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
15505 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
15506 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
15507 { 0 }
15509 static const struct message WmHotkeyPrevious[] = {
15510 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
15511 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15512 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15513 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
15514 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
15515 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
15516 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
15517 { WM_KEYDOWN, sent|lparam, 0, 1 },
15518 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
15519 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
15520 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
15521 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
15522 { 0 }
15524 static const struct message WmHotkeyNew[] = {
15525 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15526 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15527 { WM_HOTKEY, sent|wparam, 5 },
15528 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
15529 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
15530 { 0 }
15533 static int hotkey_letter;
15535 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
15537 struct recvd_message msg;
15539 if (nCode == HC_ACTION)
15541 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
15543 msg.hwnd = 0;
15544 msg.message = wParam;
15545 msg.flags = kbd_hook|wparam|lparam;
15546 msg.wParam = kdbhookstruct->vkCode;
15547 msg.lParam = kdbhookstruct->flags;
15548 msg.descr = "KeyboardHookProc";
15549 add_message(&msg);
15551 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
15553 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
15554 "unexpected keycode %x\n", kdbhookstruct->vkCode);
15558 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
15561 static void test_hotkey(void)
15563 HWND test_window, taskbar_window;
15564 BOOL ret;
15565 MSG msg;
15566 DWORD queue_status;
15567 SHORT key_state;
15569 SetLastError(0xdeadbeef);
15570 ret = UnregisterHotKey(NULL, 0);
15571 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15572 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15573 "unexpected error %d\n", GetLastError());
15575 if (ret == TRUE)
15577 skip("hotkeys not supported\n");
15578 return;
15581 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15582 100, 100, 200, 200, 0, 0, 0, NULL);
15584 flush_sequence();
15586 SetLastError(0xdeadbeef);
15587 ret = UnregisterHotKey(test_window, 0);
15588 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15589 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15590 "unexpected error %d\n", GetLastError());
15592 /* Search for a Windows Key + letter combination that hasn't been registered */
15593 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
15595 SetLastError(0xdeadbeef);
15596 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
15598 if (ret == TRUE)
15600 break;
15602 else
15604 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15605 "unexpected error %d\n", GetLastError());
15609 if (hotkey_letter == 0x52)
15611 ok(0, "Couldn't find any free Windows Key + letter combination\n");
15612 goto end;
15615 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
15616 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
15618 /* Same key combination, different id */
15619 SetLastError(0xdeadbeef);
15620 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
15621 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15622 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15623 "unexpected error %d\n", GetLastError());
15625 /* Same key combination, different window */
15626 SetLastError(0xdeadbeef);
15627 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
15628 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15629 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15630 "unexpected error %d\n", GetLastError());
15632 /* Register the same hotkey twice */
15633 SetLastError(0xdeadbeef);
15634 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
15635 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15636 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15637 "unexpected error %d\n", GetLastError());
15639 /* Window on another thread */
15640 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
15641 if (!taskbar_window)
15643 skip("no taskbar?\n");
15645 else
15647 SetLastError(0xdeadbeef);
15648 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
15649 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15650 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
15651 "unexpected error %d\n", GetLastError());
15654 /* Inject the appropriate key sequence */
15655 keybd_event(VK_LWIN, 0, 0, 0);
15656 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15657 DispatchMessageA(&msg);
15658 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
15660 keybd_event(hotkey_letter, 0, 0, 0);
15661 queue_status = GetQueueStatus(QS_HOTKEY);
15662 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
15663 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15665 if (msg.message == WM_HOTKEY)
15667 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
15668 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15670 DispatchMessageA(&msg);
15672 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
15674 queue_status = GetQueueStatus(QS_HOTKEY);
15675 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
15677 key_state = GetAsyncKeyState(hotkey_letter);
15678 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15680 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15681 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15682 DispatchMessageA(&msg);
15683 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
15685 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15686 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15687 DispatchMessageA(&msg);
15688 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
15690 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
15691 PostMessageA(test_window, WM_HOTKEY, 0, 0);
15692 queue_status = GetQueueStatus(QS_HOTKEY);
15693 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
15694 queue_status = GetQueueStatus(QS_POSTMESSAGE);
15695 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
15696 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15697 DispatchMessageA(&msg);
15698 flush_sequence();
15700 /* Send and process all messages at once */
15701 PostMessageA(test_window, WM_APP, 0, 0);
15702 keybd_event(VK_LWIN, 0, 0, 0);
15703 keybd_event(hotkey_letter, 0, 0, 0);
15704 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15705 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15707 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15709 if (msg.message == WM_HOTKEY)
15711 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
15712 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15714 DispatchMessageA(&msg);
15716 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
15718 /* Register same hwnd/id with different key combination */
15719 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
15720 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15722 /* Previous key combination does not work */
15723 keybd_event(VK_LWIN, 0, 0, 0);
15724 keybd_event(hotkey_letter, 0, 0, 0);
15725 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15726 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15728 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15729 DispatchMessageA(&msg);
15730 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
15732 /* New key combination works */
15733 keybd_event(hotkey_letter, 0, 0, 0);
15734 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15736 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15738 if (msg.message == WM_HOTKEY)
15740 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
15741 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15743 DispatchMessageA(&msg);
15745 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
15747 /* Unregister hotkey properly */
15748 ret = UnregisterHotKey(test_window, 5);
15749 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15751 /* Unregister hotkey again */
15752 SetLastError(0xdeadbeef);
15753 ret = UnregisterHotKey(test_window, 5);
15754 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15755 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15756 "unexpected error %d\n", GetLastError());
15758 /* Register thread hotkey */
15759 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
15760 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15762 /* Inject the appropriate key sequence */
15763 keybd_event(VK_LWIN, 0, 0, 0);
15764 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15766 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15767 DispatchMessageA(&msg);
15769 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
15771 keybd_event(hotkey_letter, 0, 0, 0);
15772 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15774 if (msg.message == WM_HOTKEY)
15776 struct recvd_message message;
15777 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
15778 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15779 message.message = msg.message;
15780 message.flags = sent|wparam|lparam;
15781 message.wParam = msg.wParam;
15782 message.lParam = msg.lParam;
15783 message.descr = "test_hotkey thread message";
15784 add_message(&message);
15786 else
15787 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15788 DispatchMessageA(&msg);
15790 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
15792 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15793 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15795 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15796 DispatchMessageA(&msg);
15798 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
15800 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15801 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15803 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15804 DispatchMessageA(&msg);
15806 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
15808 /* Unregister thread hotkey */
15809 ret = UnregisterHotKey(NULL, 5);
15810 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15812 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
15813 hKBD_hook = NULL;
15815 end:
15816 UnregisterHotKey(NULL, 5);
15817 UnregisterHotKey(test_window, 5);
15818 DestroyWindow(test_window);
15819 flush_sequence();
15823 static const struct message WmSetFocus_1[] = {
15824 { HCBT_SETFOCUS, hook }, /* child */
15825 { HCBT_ACTIVATE, hook }, /* parent */
15826 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
15827 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
15828 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
15829 { WM_NCACTIVATE, sent|parent },
15830 { WM_GETTEXT, sent|defwinproc|parent|optional },
15831 { WM_GETTEXT, sent|defwinproc|parent|optional },
15832 { WM_ACTIVATE, sent|wparam|parent, 1 },
15833 { HCBT_SETFOCUS, hook }, /* parent */
15834 { WM_SETFOCUS, sent|defwinproc|parent },
15835 { WM_KILLFOCUS, sent|parent },
15836 { WM_SETFOCUS, sent },
15837 { 0 }
15839 static const struct message WmSetFocus_2[] = {
15840 { HCBT_SETFOCUS, hook }, /* parent */
15841 { WM_KILLFOCUS, sent },
15842 { WM_SETFOCUS, sent|parent },
15843 { 0 }
15845 static const struct message WmSetFocus_3[] = {
15846 { HCBT_SETFOCUS, hook }, /* child */
15847 { 0 }
15850 static void test_SetFocus(void)
15852 HWND parent, old_parent, child, old_focus, old_active;
15853 MSG msg;
15854 struct wnd_event wnd_event;
15855 HANDLE hthread;
15856 DWORD ret, tid;
15858 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
15859 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
15860 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
15861 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
15862 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
15863 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
15864 CloseHandle(wnd_event.start_event);
15866 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15867 0, 0, 0, 0, 0, 0, 0, NULL);
15868 ok(parent != 0, "failed to create parent window\n");
15869 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
15870 0, 0, 0, 0, parent, 0, 0, NULL);
15871 ok(child != 0, "failed to create child window\n");
15873 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
15875 SetFocus(0);
15876 SetActiveWindow(0);
15878 flush_events();
15879 flush_sequence();
15881 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
15882 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
15884 log_all_parent_messages++;
15886 old_focus = SetFocus(child);
15887 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15888 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
15889 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
15890 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15891 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
15893 old_focus = SetFocus(parent);
15894 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15895 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
15896 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
15897 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15898 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15900 SetLastError(0xdeadbeef);
15901 old_focus = SetFocus((HWND)0xdeadbeef);
15902 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
15903 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
15904 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15905 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
15906 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
15907 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15908 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15910 SetLastError(0xdeadbeef);
15911 old_focus = SetFocus(GetDesktopWindow());
15912 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
15913 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
15914 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15915 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
15916 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
15917 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15918 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15920 SetLastError(0xdeadbeef);
15921 old_focus = SetFocus(wnd_event.hwnd);
15922 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
15923 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
15924 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15925 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
15926 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
15927 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15928 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15930 SetLastError(0xdeadbeef);
15931 old_active = SetActiveWindow((HWND)0xdeadbeef);
15932 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
15933 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
15934 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15935 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
15936 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
15937 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15938 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15940 SetLastError(0xdeadbeef);
15941 old_active = SetActiveWindow(GetDesktopWindow());
15942 todo_wine
15943 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
15944 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15945 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
15946 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
15947 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15948 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15950 SetLastError(0xdeadbeef);
15951 old_active = SetActiveWindow(wnd_event.hwnd);
15952 todo_wine
15953 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
15954 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15955 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
15956 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
15957 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15958 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15960 SetLastError(0xdeadbeef);
15961 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
15962 ok(ret, "AttachThreadInput error %d\n", GetLastError());
15964 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15965 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15967 flush_events();
15968 flush_sequence();
15970 old_focus = SetFocus(wnd_event.hwnd);
15971 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15972 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
15973 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
15974 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
15976 old_focus = SetFocus(parent);
15977 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15978 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
15979 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15980 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15982 flush_events();
15983 flush_sequence();
15985 old_active = SetActiveWindow(wnd_event.hwnd);
15986 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15987 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
15988 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
15989 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
15991 SetLastError(0xdeadbeef);
15992 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
15993 ok(ret, "AttachThreadInput error %d\n", GetLastError());
15995 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
15996 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
15998 old_parent = SetParent(child, GetDesktopWindow());
15999 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
16001 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16002 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16004 old_focus = SetFocus(parent);
16005 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16006 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16007 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16008 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16010 flush_events();
16011 flush_sequence();
16013 SetLastError(0xdeadbeef);
16014 old_focus = SetFocus(child);
16015 todo_wine
16016 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
16017 broken(GetLastError() == 0) /* XP */ ||
16018 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
16019 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16020 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
16021 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16022 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16023 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16025 SetLastError(0xdeadbeef);
16026 old_active = SetActiveWindow(child);
16027 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16028 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16029 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
16030 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
16031 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16032 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16034 log_all_parent_messages--;
16036 DestroyWindow(child);
16037 DestroyWindow(parent);
16039 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
16040 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
16041 ret = WaitForSingleObject(hthread, INFINITE);
16042 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16043 CloseHandle(hthread);
16046 static const struct message WmSetLayeredStyle[] = {
16047 { WM_STYLECHANGING, sent },
16048 { WM_STYLECHANGED, sent },
16049 { WM_GETTEXT, sent|defwinproc|optional },
16050 { 0 }
16053 static const struct message WmSetLayeredStyle2[] = {
16054 { WM_STYLECHANGING, sent },
16055 { WM_STYLECHANGED, sent },
16056 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16057 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
16058 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16059 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
16060 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
16061 { 0 }
16064 struct layered_window_info
16066 HWND hwnd;
16067 HDC hdc;
16068 SIZE size;
16069 HANDLE event;
16070 BOOL ret;
16073 static DWORD CALLBACK update_layered_proc( void *param )
16075 struct layered_window_info *info = param;
16076 POINT src = { 0, 0 };
16078 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
16079 info->hdc, &src, 0, NULL, ULW_OPAQUE );
16080 ok( info->ret, "failed\n");
16081 SetEvent( info->event );
16082 return 0;
16085 static void test_layered_window(void)
16087 HWND hwnd;
16088 HDC hdc;
16089 HBITMAP bmp;
16090 BOOL ret;
16091 SIZE size;
16092 POINT pos, src;
16093 RECT rect, client;
16094 HANDLE thread;
16095 DWORD tid;
16096 struct layered_window_info info;
16098 if (!pUpdateLayeredWindow)
16100 win_skip( "UpdateLayeredWindow not supported\n" );
16101 return;
16104 hdc = CreateCompatibleDC( 0 );
16105 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
16106 SelectObject( hdc, bmp );
16108 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
16109 100, 100, 300, 300, 0, 0, 0, NULL);
16110 ok( hwnd != 0, "failed to create window\n" );
16111 ShowWindow( hwnd, SW_SHOWNORMAL );
16112 UpdateWindow( hwnd );
16113 flush_events();
16114 flush_sequence();
16116 GetWindowRect( hwnd, &rect );
16117 GetClientRect( hwnd, &client );
16118 ok( client.right < rect.right - rect.left, "wrong client area\n" );
16119 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
16121 src.x = src.y = 0;
16122 pos.x = pos.y = 300;
16123 size.cx = size.cy = 250;
16124 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16125 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16126 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16127 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16128 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16130 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16131 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16132 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16133 GetWindowRect( hwnd, &rect );
16134 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
16135 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16136 GetClientRect( hwnd, &rect );
16137 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
16138 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16140 size.cx = 150;
16141 pos.y = 200;
16142 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16143 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16144 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16145 GetWindowRect( hwnd, &rect );
16146 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
16147 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16148 GetClientRect( hwnd, &rect );
16149 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
16150 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16152 SetWindowLongA( hwnd, GWL_STYLE,
16153 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
16154 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
16156 size.cx = 200;
16157 pos.x = 200;
16158 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16159 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16160 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16161 GetWindowRect( hwnd, &rect );
16162 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16163 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16164 GetClientRect( hwnd, &rect );
16165 ok( (rect.right == 200 && rect.bottom == 250) ||
16166 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16167 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16169 size.cx = 0;
16170 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16171 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16172 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
16173 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
16174 size.cx = 1;
16175 size.cy = -1;
16176 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16177 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16178 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16180 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
16181 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16182 GetWindowRect( hwnd, &rect );
16183 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16184 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16185 GetClientRect( hwnd, &rect );
16186 ok( (rect.right == 200 && rect.bottom == 250) ||
16187 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16188 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16190 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16191 info.hwnd = hwnd;
16192 info.hdc = hdc;
16193 info.size.cx = 250;
16194 info.size.cy = 300;
16195 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
16196 info.ret = FALSE;
16197 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
16198 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
16199 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
16200 WaitForSingleObject( thread, 1000 );
16201 CloseHandle( thread );
16202 GetWindowRect( hwnd, &rect );
16203 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
16204 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16205 GetClientRect( hwnd, &rect );
16206 ok( (rect.right == 250 && rect.bottom == 300) ||
16207 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
16208 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16210 DestroyWindow( hwnd );
16211 DeleteDC( hdc );
16212 DeleteObject( bmp );
16215 static HMENU hpopupmenu;
16217 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16219 if (ignore_message( message )) return 0;
16221 switch (message) {
16222 case WM_ENTERIDLE:
16223 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
16224 EndMenu();
16225 break;
16226 case WM_INITMENU:
16227 case WM_INITMENUPOPUP:
16228 case WM_UNINITMENUPOPUP:
16229 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
16230 break;
16231 case WM_CAPTURECHANGED:
16232 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
16233 break;
16236 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16239 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16241 if (ignore_message( message )) return 0;
16243 switch (message) {
16244 case WM_ENTERMENULOOP:
16245 ok(EndMenu() == TRUE, "EndMenu() failed\n");
16246 break;
16249 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16252 static void test_TrackPopupMenu(void)
16254 MSG msg;
16255 HWND hwnd;
16256 BOOL ret;
16258 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16259 0, 0, 1, 1, 0,
16260 NULL, NULL, 0);
16261 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16263 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16265 hpopupmenu = CreatePopupMenu();
16266 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16268 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
16269 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
16271 flush_events();
16272 flush_sequence();
16273 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16274 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
16275 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16277 /* Test popup closing with an ESC-press */
16278 flush_events();
16279 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
16280 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16281 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16282 PostQuitMessage(0);
16283 flush_sequence();
16284 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
16286 TranslateMessage(&msg);
16287 DispatchMessageA(&msg);
16289 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
16291 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
16293 flush_events();
16294 flush_sequence();
16295 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16296 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
16297 ok(ret == TRUE, "TrackPopupMenu failed\n");
16299 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16301 SetCapture(hwnd);
16303 flush_events();
16304 flush_sequence();
16305 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16306 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
16307 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
16309 DestroyMenu(hpopupmenu);
16310 DestroyWindow(hwnd);
16313 static void test_TrackPopupMenuEmpty(void)
16315 HWND hwnd;
16316 BOOL ret;
16318 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16319 0, 0, 1, 1, 0,
16320 NULL, NULL, 0);
16321 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16323 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16325 hpopupmenu = CreatePopupMenu();
16326 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16328 flush_events();
16329 flush_sequence();
16330 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16331 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
16332 ok(ret == 0, "TrackPopupMenu succeeded\n");
16334 DestroyMenu(hpopupmenu);
16335 DestroyWindow(hwnd);
16338 static const struct message send_message_1[] = {
16339 { WM_USER+2, sent|wparam|lparam, 0, 0 },
16340 { WM_USER, sent|wparam|lparam, 0, 0 },
16341 { 0 }
16343 static const struct message send_message_2[] = {
16344 { WM_USER+4, sent|wparam|lparam, 0, 0 },
16345 { 0 }
16347 static const struct message send_message_3[] = {
16348 { WM_USER+3, sent|wparam|lparam, 0, 0 },
16349 { 0 }
16351 static const struct message send_message_4[] = {
16352 { WM_USER+1, sent|wparam|lparam, 0, 0 },
16353 { 0 }
16356 static DWORD WINAPI SendMessage_thread_1(void *param)
16358 struct wnd_event *wnd_event = param;
16360 trace("thread: starting\n");
16361 WaitForSingleObject(wnd_event->start_event, INFINITE);
16363 trace("thread: call PostMessage\n");
16364 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16366 trace("thread: call PostMessage\n");
16367 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16369 trace("thread: call SendMessage\n");
16370 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16372 trace("thread: call SendMessage\n");
16373 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16375 return 0;
16378 static DWORD WINAPI SendMessage_thread_2(void *param)
16380 struct wnd_event *wnd_event = param;
16382 trace("thread: starting\n");
16383 WaitForSingleObject(wnd_event->start_event, INFINITE);
16385 trace("thread: call PostMessage\n");
16386 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16388 trace("thread: call PostMessage\n");
16389 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16391 /* this leads to sending an internal message under Wine */
16392 trace("thread: call SetParent\n");
16393 SetParent(wnd_event->hwnd, wnd_event->hwnd);
16395 trace("thread: call SendMessage\n");
16396 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16398 trace("thread: call SendMessage\n");
16399 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16401 return 0;
16404 static void test_SendMessage_other_thread(int thread_n)
16406 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
16407 HANDLE hthread;
16408 struct wnd_event wnd_event;
16409 DWORD tid, ret;
16410 MSG msg;
16412 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
16414 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
16415 100, 100, 200, 200, 0, 0, 0, NULL);
16416 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
16418 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
16419 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
16420 CloseHandle(hthread);
16422 flush_events();
16423 flush_sequence();
16425 ret = GetQueueStatus(QS_SENDMESSAGE);
16426 ok(ret == 0, "wrong status %08x\n", ret);
16428 SetEvent(wnd_event.start_event);
16430 /* wait for other thread's SendMessage */
16431 for (;;)
16433 ret = GetQueueStatus(QS_SENDMESSAGE);
16434 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
16435 Sleep(50);
16438 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16439 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
16441 trace("main: call GetMessage\n");
16442 GetMessageA(&msg, 0, 0, 0);
16443 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
16444 DispatchMessageA(&msg);
16445 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
16447 /* intentionally yield */
16448 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
16450 trace("main: call SendMessage\n");
16451 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
16452 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
16454 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16455 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
16457 trace("main: call PeekMessage\n");
16458 ok(PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "PeekMessage should not fail\n");
16459 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
16460 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
16462 trace("main: call PeekMessage\n");
16463 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
16464 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
16465 DispatchMessageA(&msg);
16466 ok_sequence(send_message_4, "SendMessage from other thread 4", FALSE);
16468 /* intentionally yield */
16469 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
16471 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16472 /* FIXME: remove once Wine is fixed */
16473 todo_wine_if (thread_n == 2)
16474 ok(ret == 0, "wrong status %08x\n", ret);
16476 trace("main: call PeekMessage\n");
16477 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
16478 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
16480 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16481 ok(ret == 0, "wrong status %08x\n", ret);
16483 trace("main: call DestroyWindow\n");
16484 DestroyWindow(msg.hwnd);
16486 flush_events();
16487 flush_sequence();
16490 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
16492 DWORD flags = InSendMessageEx( NULL );
16493 BOOL ret;
16495 switch (msg)
16497 case WM_USER:
16498 ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
16499 ok( InSendMessage(), "InSendMessage returned false\n" );
16500 ret = ReplyMessage( msg );
16501 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
16502 flags = InSendMessageEx( NULL );
16503 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
16504 ok( InSendMessage(), "InSendMessage returned false\n" );
16505 break;
16506 case WM_USER + 1:
16507 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
16508 ok( InSendMessage(), "InSendMessage returned false\n" );
16509 ret = ReplyMessage( msg );
16510 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
16511 flags = InSendMessageEx( NULL );
16512 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
16513 ok( InSendMessage(), "InSendMessage returned false\n" );
16514 break;
16515 case WM_USER + 2:
16516 ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
16517 ok( InSendMessage(), "InSendMessage returned false\n" );
16518 ret = ReplyMessage( msg );
16519 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
16520 flags = InSendMessageEx( NULL );
16521 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
16522 ok( InSendMessage(), "InSendMessage returned false\n" );
16523 break;
16524 case WM_USER + 3:
16525 ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
16526 ok( !InSendMessage(), "InSendMessage returned true\n" );
16527 ret = ReplyMessage( msg );
16528 ok( !ret, "ReplyMessage succeeded\n" );
16529 break;
16532 return DefWindowProcA( hwnd, msg, wp, lp );
16535 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
16537 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
16538 ok( result == WM_USER + 2, "wrong result %lx\n", result );
16541 static DWORD WINAPI send_message_thread( void *arg )
16543 HWND win = arg;
16545 SendMessageA( win, WM_USER, 0, 0 );
16546 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
16547 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
16548 PostMessageA( win, WM_USER + 3, 0, 0 );
16549 PostMessageA( win, WM_QUIT, 0, 0 );
16550 return 0;
16553 static void test_InSendMessage(void)
16555 WNDCLASSA cls;
16556 HWND win;
16557 MSG msg;
16558 HANDLE thread;
16559 DWORD tid;
16561 memset(&cls, 0, sizeof(cls));
16562 cls.lpfnWndProc = insendmessage_wnd_proc;
16563 cls.hInstance = GetModuleHandleA(NULL);
16564 cls.lpszClassName = "InSendMessage_test";
16565 RegisterClassA(&cls);
16567 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
16568 ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
16570 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
16571 ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
16573 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
16575 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
16576 CloseHandle( thread );
16578 DestroyWindow( win );
16579 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
16582 static const struct message DoubleSetCaptureSeq[] =
16584 { WM_CAPTURECHANGED, sent },
16585 { 0 }
16588 static void test_DoubleSetCapture(void)
16590 HWND hwnd;
16592 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
16593 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16594 100, 100, 200, 200, 0, 0, 0, NULL);
16595 ok (hwnd != 0, "Failed to create overlapped window\n");
16597 ShowWindow( hwnd, SW_SHOW );
16598 UpdateWindow( hwnd );
16599 flush_events();
16600 flush_sequence();
16602 SetCapture( hwnd );
16603 SetCapture( hwnd );
16604 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
16606 DestroyWindow(hwnd);
16609 static void init_funcs(void)
16611 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
16613 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
16614 X(ActivateActCtx);
16615 X(CreateActCtxW);
16616 X(DeactivateActCtx);
16617 X(GetCurrentActCtx);
16618 X(QueryActCtxW);
16619 X(ReleaseActCtx);
16620 #undef X
16623 START_TEST(msg)
16625 char **test_argv;
16626 BOOL ret;
16627 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
16628 HMODULE hModuleImm32;
16629 BOOL (WINAPI *pImmDisableIME)(DWORD);
16630 int argc;
16632 init_funcs();
16634 argc = winetest_get_mainargs( &test_argv );
16635 if (argc >= 3)
16637 unsigned int arg;
16638 /* Child process. */
16639 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
16640 do_wait_idle_child( arg );
16641 return;
16644 InitializeCriticalSection( &sequence_cs );
16645 init_procs();
16647 hModuleImm32 = LoadLibraryA("imm32.dll");
16648 if (hModuleImm32) {
16649 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
16650 if (pImmDisableIME)
16651 pImmDisableIME(0);
16653 pImmDisableIME = NULL;
16654 FreeLibrary(hModuleImm32);
16656 if (!RegisterWindowClasses()) assert(0);
16658 if (pSetWinEventHook)
16660 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
16661 GetModuleHandleA(0), win_event_proc,
16662 0, GetCurrentThreadId(),
16663 WINEVENT_INCONTEXT);
16664 if (pIsWinEventHookInstalled && hEvent_hook)
16666 UINT event;
16667 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
16668 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
16671 if (!hEvent_hook) win_skip( "no win event hook support\n" );
16673 cbt_hook_thread_id = GetCurrentThreadId();
16674 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
16675 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
16677 test_winevents();
16679 /* Fix message sequences before removing 4 lines below */
16680 if (pUnhookWinEvent && hEvent_hook)
16682 ret = pUnhookWinEvent(hEvent_hook);
16683 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
16684 pUnhookWinEvent = 0;
16686 hEvent_hook = 0;
16688 test_SendMessage_other_thread(1);
16689 test_SendMessage_other_thread(2);
16690 test_InSendMessage();
16691 test_SetFocus();
16692 test_SetParent();
16693 test_PostMessage();
16694 test_broadcast();
16695 test_ShowWindow();
16696 test_PeekMessage();
16697 test_PeekMessage2();
16698 test_PeekMessage3();
16699 test_WaitForInputIdle( test_argv[0] );
16700 test_scrollwindowex();
16701 test_messages();
16702 test_setwindowpos();
16703 test_showwindow();
16704 invisible_parent_tests();
16705 test_mdi_messages();
16706 test_button_messages();
16707 test_static_messages();
16708 test_listbox_messages();
16709 test_combobox_messages();
16710 test_wmime_keydown_message();
16711 test_paint_messages();
16712 test_interthread_messages();
16713 test_message_conversion();
16714 test_accelerators();
16715 test_timers();
16716 test_timers_no_wnd();
16717 test_timers_exceptions();
16718 if (hCBT_hook)
16720 test_set_hook();
16721 test_recursive_hook();
16723 test_DestroyWindow();
16724 test_DispatchMessage();
16725 test_SendMessageTimeout();
16726 test_edit_messages();
16727 test_quit_message();
16728 test_notify_message();
16729 test_SetActiveWindow();
16731 if (!pTrackMouseEvent)
16732 win_skip("TrackMouseEvent is not available\n");
16733 else
16734 test_TrackMouseEvent();
16736 test_SetWindowRgn();
16737 test_sys_menu();
16738 test_dialog_messages();
16739 test_EndDialog();
16740 test_nullCallback();
16741 test_dbcs_wm_char();
16742 test_unicode_wm_char();
16743 test_menu_messages();
16744 test_paintingloop();
16745 test_defwinproc();
16746 test_clipboard_viewers();
16747 test_keyflags();
16748 test_hotkey();
16749 test_layered_window();
16750 test_TrackPopupMenu();
16751 test_TrackPopupMenuEmpty();
16752 test_DoubleSetCapture();
16753 /* keep it the last test, under Windows it tends to break the tests
16754 * which rely on active/foreground windows being correct.
16756 test_SetForegroundWindow();
16758 UnhookWindowsHookEx(hCBT_hook);
16759 if (pUnhookWinEvent && hEvent_hook)
16761 ret = pUnhookWinEvent(hEvent_hook);
16762 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
16763 SetLastError(0xdeadbeef);
16764 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
16765 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
16766 GetLastError() == 0xdeadbeef, /* Win9x */
16767 "unexpected error %d\n", GetLastError());
16769 DeleteCriticalSection( &sequence_cs );