push 73336d9f381967eae40f391d78198b916ed9848d
[wine/hacks.git] / dlls / user32 / tests / msg.c
blob69bba8bce7a3a01bd293f6dbadb3e4a735565b2f
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 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
27 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
35 #include "wine/test.h"
37 #define MDI_FIRST_CHILD_ID 2004
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE 0x0800
41 #define SWP_NOCLIENTMOVE 0x1000
42 #define SWP_STATECHANGED 0x8000
44 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
46 #ifndef WM_SYSTIMER
47 #define WM_SYSTIMER 0x0118
48 #endif
50 #define WND_PARENT_ID 1
51 #define WND_POPUP_ID 2
52 #define WND_CHILD_ID 3
54 #ifndef WM_LBTRACKPOINT
55 #define WM_LBTRACKPOINT 0x0131
56 #endif
58 /* encoded DRAWITEMSTRUCT into an LPARAM */
59 typedef struct
61 union
63 struct
65 UINT type : 4; /* ODT_* flags */
66 UINT ctl_id : 4; /* Control ID */
67 UINT item_id : 4; /* Menu item ID */
68 UINT action : 4; /* ODA_* flags */
69 UINT state : 16; /* ODS_* flags */
70 } item;
71 LPARAM lp;
72 } u;
73 } DRAW_ITEM_STRUCT;
75 static BOOL test_DestroyWindow_flag;
76 static HWINEVENTHOOK hEvent_hook;
78 static void dump_winpos_flags(UINT flags);
80 static const WCHAR testWindowClassW[] =
81 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
84 FIXME: add tests for these
85 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
86 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
87 WS_THICKFRAME: thick border
88 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
89 WS_BORDER (default for overlapped windows): single black border
90 none (default for child (and popup?) windows): no border
93 typedef enum {
94 sent=0x1,
95 posted=0x2,
96 parent=0x4,
97 wparam=0x8,
98 lparam=0x10,
99 defwinproc=0x20,
100 beginpaint=0x40,
101 optional=0x80,
102 hook=0x100,
103 winevent_hook=0x200
104 } msg_flags_t;
106 struct message {
107 UINT message; /* the WM_* code */
108 msg_flags_t flags; /* message props */
109 WPARAM wParam; /* expected value of wParam */
110 LPARAM lParam; /* expected value of lParam */
113 /* Empty message sequence */
114 static const struct message WmEmptySeq[] =
116 { 0 }
118 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
119 static const struct message WmCreateOverlappedSeq[] = {
120 { HCBT_CREATEWND, hook },
121 { WM_GETMINMAXINFO, sent },
122 { WM_NCCREATE, sent },
123 { WM_NCCALCSIZE, sent|wparam, 0 },
124 { 0x0093, sent|defwinproc|optional },
125 { 0x0094, sent|defwinproc|optional },
126 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
127 { WM_CREATE, sent },
128 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
129 { 0 }
131 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
132 * for a not visible overlapped window.
134 static const struct message WmSWP_ShowOverlappedSeq[] = {
135 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
136 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
137 { WM_NCPAINT, sent|wparam|optional, 1 },
138 { WM_GETTEXT, sent|defwinproc|optional },
139 { WM_ERASEBKGND, sent|optional },
140 { HCBT_ACTIVATE, hook },
141 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
142 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
143 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
144 { WM_ACTIVATEAPP, sent|wparam, 1 },
145 { WM_NCACTIVATE, sent|wparam, 1 },
146 { WM_GETTEXT, sent|defwinproc|optional },
147 { WM_ACTIVATE, sent|wparam, 1 },
148 { HCBT_SETFOCUS, hook },
149 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
150 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
151 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
152 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
153 { WM_NCPAINT, sent|wparam|optional, 1 },
154 { WM_GETTEXT, sent|defwinproc|optional },
155 { WM_ERASEBKGND, sent|optional },
156 /* Win9x adds SWP_NOZORDER below */
157 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
158 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
159 { WM_NCPAINT, sent|wparam|optional, 1 },
160 { WM_ERASEBKGND, sent|optional },
161 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
162 { 0 }
164 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
165 * for a visible overlapped window.
167 static const struct message WmSWP_HideOverlappedSeq[] = {
168 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
169 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
170 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
171 { 0 }
174 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
175 * for a visible overlapped window.
177 static const struct message WmSWP_ResizeSeq[] = {
178 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
179 { WM_GETMINMAXINFO, sent|defwinproc },
180 { WM_NCCALCSIZE, sent|wparam, TRUE },
181 { WM_NCPAINT, sent|optional },
182 { WM_GETTEXT, sent|defwinproc|optional },
183 { WM_ERASEBKGND, sent|optional },
184 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
185 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
186 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
187 { WM_NCPAINT, sent|optional },
188 { WM_GETTEXT, sent|defwinproc|optional },
189 { WM_ERASEBKGND, sent|optional },
190 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
191 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
192 { 0 }
195 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
196 * for a visible popup window.
198 static const struct message WmSWP_ResizePopupSeq[] = {
199 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
200 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
201 { WM_NCCALCSIZE, sent|wparam, TRUE },
202 { WM_NCPAINT, sent|optional },
203 { WM_GETTEXT, sent|defwinproc|optional },
204 { WM_ERASEBKGND, sent|optional },
205 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
206 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
207 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
208 { WM_NCPAINT, sent|optional },
209 { WM_GETTEXT, sent|defwinproc|optional },
210 { WM_ERASEBKGND, sent|optional },
211 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
212 { 0 }
215 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
216 * for a visible overlapped window.
218 static const struct message WmSWP_MoveSeq[] = {
219 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
220 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
221 { WM_MOVE, sent|defwinproc|wparam, 0 },
222 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
223 { 0 }
225 /* Resize with SetWindowPos(SWP_NOZORDER)
226 * for a visible overlapped window
227 * SWP_NOZORDER is stripped by the logging code
229 static const struct message WmSWP_ResizeNoZOrder[] = {
230 { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ },
231 { WM_GETMINMAXINFO, sent|defwinproc },
232 { WM_NCCALCSIZE, sent|wparam, 1 },
233 { WM_NCPAINT, sent },
234 { WM_GETTEXT, sent|defwinproc|optional },
235 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
236 { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE },
237 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
238 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
239 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
240 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
241 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
242 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
243 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
244 { 0 }
247 /* Switch visible mdi children */
248 static const struct message WmSwitchChild[] = {
249 /* Switch MDI child */
250 { WM_MDIACTIVATE, sent },/* in the MDI client */
251 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
252 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
253 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
254 /* Deactivate 2nd MDI child */
255 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
256 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
257 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
258 /* Preparing for maximize and maximaze the 1st MDI child */
259 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
260 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
261 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
262 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
263 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 }, /* in the 1st MDI child */
264 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
265 /* Lock redraw 2nd MDI child */
266 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
267 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
268 /* Restore 2nd MDI child */
269 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },/* in the 2nd MDI child */
270 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
271 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
272 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 }, /* in the 2nd MDI child */
273 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
274 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
275 /* Redraw 2nd MDI child */
276 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
277 /* Redraw MDI frame */
278 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
279 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
280 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
281 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
282 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
283 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
284 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
285 { HCBT_SETFOCUS, hook },
286 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
287 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
288 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
289 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
290 { WM_SETFOCUS, sent },/* in the MDI client */
291 { HCBT_SETFOCUS, hook },
292 { WM_KILLFOCUS, sent },/* in the MDI client */
293 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
294 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
295 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
296 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
297 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
298 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
299 { 0 }
302 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
303 SWP_NOZORDER|SWP_FRAMECHANGED)
304 * for a visible overlapped window with WS_CLIPCHILDREN style set.
306 static const struct message WmSWP_FrameChanged_clip[] = {
307 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
308 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
309 { WM_NCPAINT, sent|parent }, /* wparam != 1 */
310 { WM_GETTEXT, sent|parent|defwinproc|optional },
311 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
312 { WM_NCPAINT, sent }, /* wparam != 1 */
313 { WM_ERASEBKGND, sent },
314 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
315 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
316 { WM_PAINT, sent },
317 { 0 }
319 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
320 SWP_NOZORDER|SWP_FRAMECHANGED)
321 * for a visible overlapped window.
323 static const struct message WmSWP_FrameChangedDeferErase[] = {
324 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
325 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
326 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
327 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
328 { WM_PAINT, sent|parent },
329 { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
330 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
331 { WM_PAINT, sent },
332 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
333 { WM_ERASEBKGND, sent|beginpaint },
334 { 0 }
337 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
338 SWP_NOZORDER|SWP_FRAMECHANGED)
339 * for a visible overlapped window without WS_CLIPCHILDREN style set.
341 static const struct message WmSWP_FrameChanged_noclip[] = {
342 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
343 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
344 { WM_NCPAINT, sent|parent }, /* wparam != 1 */
345 { WM_GETTEXT, sent|parent|defwinproc|optional },
346 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
347 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
348 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
349 { WM_PAINT, sent },
350 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
351 { WM_ERASEBKGND, sent|beginpaint },
352 { 0 }
355 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
356 static const struct message WmShowOverlappedSeq[] = {
357 { WM_SHOWWINDOW, sent|wparam, 1 },
358 { WM_NCPAINT, sent|wparam|optional, 1 },
359 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
360 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
361 { WM_NCPAINT, sent|wparam|optional, 1 },
362 { WM_GETTEXT, sent|defwinproc|optional },
363 { WM_ERASEBKGND, sent|optional },
364 { HCBT_ACTIVATE, hook },
365 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
366 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
367 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
368 { WM_NCPAINT, sent|wparam|optional, 1 },
369 { WM_ACTIVATEAPP, sent|wparam, 1 },
370 { WM_NCACTIVATE, sent|wparam, 1 },
371 { WM_GETTEXT, sent|defwinproc|optional },
372 { WM_ACTIVATE, sent|wparam, 1 },
373 { HCBT_SETFOCUS, hook },
374 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
375 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
376 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
377 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
378 { WM_NCPAINT, sent|wparam|optional, 1 },
379 { WM_GETTEXT, sent|defwinproc|optional },
380 { WM_ERASEBKGND, sent|optional },
381 /* Win9x adds SWP_NOZORDER below */
382 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
383 { WM_NCCALCSIZE, sent|optional },
384 { WM_NCPAINT, sent|optional },
385 { WM_ERASEBKGND, sent|optional },
386 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
387 * messages. Does that mean that CreateWindow doesn't set initial
388 * window dimensions for overlapped windows?
390 { WM_SIZE, sent },
391 { WM_MOVE, sent },
392 #endif
393 { 0 }
395 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
396 static const struct message WmShowMaxOverlappedSeq[] = {
397 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
398 { WM_GETMINMAXINFO, sent },
399 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
400 { WM_GETMINMAXINFO, sent|defwinproc },
401 { WM_NCCALCSIZE, sent|wparam, TRUE },
402 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
403 { HCBT_ACTIVATE, hook },
404 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
405 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
406 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
407 { WM_ACTIVATEAPP, sent|wparam, 1 },
408 { WM_NCACTIVATE, sent|wparam, 1 },
409 { WM_GETTEXT, sent|defwinproc|optional },
410 { WM_ACTIVATE, sent|wparam, 1 },
411 { HCBT_SETFOCUS, hook },
412 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
413 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
414 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
415 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
416 { WM_NCPAINT, sent|wparam|optional, 1 },
417 { WM_GETTEXT, sent|defwinproc|optional },
418 { WM_ERASEBKGND, sent|optional },
419 /* Win9x adds SWP_NOZORDER below */
420 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
421 { WM_MOVE, sent|defwinproc },
422 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
423 { WM_NCCALCSIZE, sent|optional },
424 { WM_NCPAINT, sent|optional },
425 { WM_ERASEBKGND, sent|optional },
426 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
427 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
428 { 0 }
430 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
431 static const struct message WmShowMinOverlappedSeq[] = {
432 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
433 { HCBT_SETFOCUS, hook },
434 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
435 { WM_KILLFOCUS, sent },
436 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
437 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
438 { WM_GETTEXT, sent|optional },
439 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
440 { WM_GETMINMAXINFO, sent|defwinproc },
441 { WM_NCCALCSIZE, sent|wparam, TRUE },
442 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
443 { WM_NCPAINT, sent },
444 { WM_GETTEXT, sent|defwinproc|optional },
445 { WM_WINDOWPOSCHANGED, sent },
446 { WM_MOVE, sent|defwinproc },
447 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
448 { WM_NCCALCSIZE, sent|optional },
449 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
450 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
451 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
452 { WM_NCACTIVATE, sent|wparam, 0 },
453 { WM_GETTEXT, sent|defwinproc|optional },
454 { WM_ACTIVATE, sent },
455 { WM_ACTIVATEAPP, sent|wparam, 0 },
456 { 0 }
458 /* ShowWindow(SW_HIDE) for a visible overlapped window */
459 static const struct message WmHideOverlappedSeq[] = {
460 { WM_SHOWWINDOW, sent|wparam, 0 },
461 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
462 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
463 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
464 { WM_SIZE, sent|optional }, /* XP doesn't send it */
465 { WM_MOVE, sent|optional }, /* XP doesn't send it */
466 { WM_NCACTIVATE, sent|wparam, 0 },
467 { WM_ACTIVATE, sent|wparam, 0 },
468 { WM_ACTIVATEAPP, sent|wparam, 0 },
469 { WM_KILLFOCUS, sent|wparam, 0 },
470 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
471 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
472 { 0 }
474 /* DestroyWindow for a visible overlapped window */
475 static const struct message WmDestroyOverlappedSeq[] = {
476 { HCBT_DESTROYWND, hook },
477 { 0x0090, sent|optional },
478 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
479 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
480 { 0x0090, sent|optional },
481 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
482 { WM_NCACTIVATE, sent|wparam, 0 },
483 { WM_ACTIVATE, sent|wparam, 0 },
484 { WM_ACTIVATEAPP, sent|wparam, 0 },
485 { WM_KILLFOCUS, sent|wparam, 0 },
486 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
487 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
488 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
489 { WM_DESTROY, sent },
490 { WM_NCDESTROY, sent },
491 { 0 }
493 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
494 static const struct message WmCreateMaxPopupSeq[] = {
495 { HCBT_CREATEWND, hook },
496 { WM_NCCREATE, sent },
497 { WM_NCCALCSIZE, sent|wparam, 0 },
498 { WM_CREATE, sent },
499 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
500 { WM_SIZE, sent|wparam, SIZE_RESTORED },
501 { WM_MOVE, sent },
502 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
503 { WM_GETMINMAXINFO, sent },
504 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
505 { WM_NCCALCSIZE, sent|wparam, TRUE },
506 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
507 { WM_MOVE, sent|defwinproc },
508 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
509 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
510 { WM_SHOWWINDOW, sent|wparam, 1 },
511 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
512 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
513 { HCBT_ACTIVATE, hook },
514 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
515 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
516 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
517 { WM_ACTIVATEAPP, sent|wparam, 1 },
518 { WM_NCACTIVATE, sent|wparam, 1 },
519 { WM_ACTIVATE, sent|wparam, 1 },
520 { HCBT_SETFOCUS, hook },
521 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
522 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
523 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
524 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
525 { WM_SYNCPAINT, sent|wparam|optional, 4 },
526 { WM_NCPAINT, sent|wparam|optional, 1 },
527 { WM_ERASEBKGND, sent|optional },
528 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
529 { 0 }
531 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
532 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
533 { HCBT_CREATEWND, hook },
534 { WM_NCCREATE, sent },
535 { WM_NCCALCSIZE, sent|wparam, 0 },
536 { WM_CREATE, sent },
537 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
538 { WM_SIZE, sent|wparam, SIZE_RESTORED },
539 { WM_MOVE, sent },
540 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
541 { WM_GETMINMAXINFO, sent },
542 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
543 { WM_NCCALCSIZE, sent|wparam, TRUE },
544 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
545 { WM_MOVE, sent|defwinproc },
546 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
547 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
548 { 0 }
550 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
551 static const struct message WmShowMaxPopupResizedSeq[] = {
552 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
553 { WM_GETMINMAXINFO, sent },
554 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
555 { WM_NCCALCSIZE, sent|wparam, TRUE },
556 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
557 { HCBT_ACTIVATE, hook },
558 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
559 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
560 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
561 { WM_ACTIVATEAPP, sent|wparam, 1 },
562 { WM_NCACTIVATE, sent|wparam, 1 },
563 { WM_ACTIVATE, sent|wparam, 1 },
564 { HCBT_SETFOCUS, hook },
565 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
566 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
567 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
568 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
569 { WM_NCPAINT, sent|wparam|optional, 1 },
570 { WM_ERASEBKGND, sent|optional },
571 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE },
572 /* WinNT4.0 sends WM_MOVE */
573 { WM_MOVE, sent|defwinproc|optional },
574 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
575 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
576 { 0 }
578 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
579 static const struct message WmShowMaxPopupSeq[] = {
580 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
581 { WM_GETMINMAXINFO, sent },
582 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
583 { WM_NCCALCSIZE, sent|wparam, TRUE },
584 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
585 { HCBT_ACTIVATE, hook },
586 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
587 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
588 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
589 { WM_ACTIVATEAPP, sent|wparam, 1 },
590 { WM_NCACTIVATE, sent|wparam, 1 },
591 { WM_ACTIVATE, sent|wparam, 1 },
592 { HCBT_SETFOCUS, hook },
593 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
594 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
595 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
596 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
597 { WM_SYNCPAINT, sent|wparam|optional, 4 },
598 { WM_NCPAINT, sent|wparam|optional, 1 },
599 { WM_ERASEBKGND, sent|optional },
600 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
601 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
602 { 0 }
604 /* CreateWindow(WS_VISIBLE) for popup window */
605 static const struct message WmCreatePopupSeq[] = {
606 { HCBT_CREATEWND, hook },
607 { WM_NCCREATE, sent },
608 { WM_NCCALCSIZE, sent|wparam, 0 },
609 { WM_CREATE, sent },
610 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
611 { WM_SIZE, sent|wparam, SIZE_RESTORED },
612 { WM_MOVE, sent },
613 { WM_SHOWWINDOW, sent|wparam, 1 },
614 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
615 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
616 { HCBT_ACTIVATE, hook },
617 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
618 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
619 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
620 { WM_NCPAINT, sent|wparam|optional, 1 },
621 { WM_ERASEBKGND, sent|optional },
622 { WM_ACTIVATEAPP, sent|wparam, 1 },
623 { WM_NCACTIVATE, sent|wparam, 1 },
624 { WM_ACTIVATE, sent|wparam, 1 },
625 { HCBT_SETFOCUS, hook },
626 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
627 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
628 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
629 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
630 { WM_SYNCPAINT, sent|wparam|optional, 4 },
631 { WM_NCPAINT, sent|wparam|optional, 1 },
632 { WM_ERASEBKGND, sent|optional },
633 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
634 { 0 }
636 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
637 static const struct message WmShowVisMaxPopupSeq[] = {
638 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
639 { WM_GETMINMAXINFO, sent },
640 { WM_GETTEXT, sent|optional },
641 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
642 { WM_NCCALCSIZE, sent|wparam, TRUE },
643 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
644 { WM_NCPAINT, sent|wparam|optional, 1 },
645 { WM_ERASEBKGND, sent|optional },
646 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
647 { WM_MOVE, sent|defwinproc },
648 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
649 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
650 { 0 }
652 /* CreateWindow (for a child popup window, not initially visible) */
653 static const struct message WmCreateChildPopupSeq[] = {
654 { HCBT_CREATEWND, hook },
655 { WM_NCCREATE, sent },
656 { WM_NCCALCSIZE, sent|wparam, 0 },
657 { WM_CREATE, sent },
658 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
659 { WM_SIZE, sent|wparam, SIZE_RESTORED },
660 { WM_MOVE, sent },
661 { 0 }
663 /* CreateWindow (for a popup window, not initially visible,
664 * which sets WS_VISIBLE in WM_CREATE handler)
666 static const struct message WmCreateInvisiblePopupSeq[] = {
667 { HCBT_CREATEWND, hook },
668 { WM_NCCREATE, sent },
669 { WM_NCCALCSIZE, sent|wparam, 0 },
670 { WM_CREATE, sent },
671 { WM_STYLECHANGING, sent },
672 { WM_STYLECHANGED, sent },
673 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
674 { WM_SIZE, sent|wparam, SIZE_RESTORED },
675 { WM_MOVE, sent },
676 { 0 }
678 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
679 * for a popup window with WS_VISIBLE style set
681 static const struct message WmShowVisiblePopupSeq_2[] = {
682 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
683 { 0 }
685 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
686 * for a popup window with WS_VISIBLE style set
688 static const struct message WmShowVisiblePopupSeq_3[] = {
689 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
690 { HCBT_ACTIVATE, hook },
691 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
692 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
693 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
694 { WM_NCACTIVATE, sent|wparam, 1 },
695 { WM_ACTIVATE, sent|wparam, 1 },
696 { HCBT_SETFOCUS, hook },
697 { WM_KILLFOCUS, sent|parent },
698 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
699 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
700 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
701 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
702 { WM_SETFOCUS, sent|defwinproc },
703 { 0 }
705 /* CreateWindow (for child window, not initially visible) */
706 static const struct message WmCreateChildSeq[] = {
707 { HCBT_CREATEWND, hook },
708 { WM_NCCREATE, sent },
709 /* child is inserted into parent's child list after WM_NCCREATE returns */
710 { WM_NCCALCSIZE, sent|wparam, 0 },
711 { WM_CREATE, sent },
712 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
713 { WM_SIZE, sent|wparam, SIZE_RESTORED },
714 { WM_MOVE, sent },
715 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
716 { 0 }
718 /* CreateWindow (for maximized child window, not initially visible) */
719 static const struct message WmCreateMaximizedChildSeq[] = {
720 { HCBT_CREATEWND, hook },
721 { WM_NCCREATE, sent },
722 { WM_NCCALCSIZE, sent|wparam, 0 },
723 { WM_CREATE, sent },
724 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
725 { WM_SIZE, sent|wparam, SIZE_RESTORED },
726 { WM_MOVE, sent },
727 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
728 { WM_GETMINMAXINFO, sent },
729 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
730 { WM_NCCALCSIZE, sent|wparam, 1 },
731 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
732 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
733 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
734 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
735 { 0 }
737 /* CreateWindow (for a child window, initially visible) */
738 static const struct message WmCreateVisibleChildSeq[] = {
739 { HCBT_CREATEWND, hook },
740 { WM_NCCREATE, sent },
741 /* child is inserted into parent's child list after WM_NCCREATE returns */
742 { WM_NCCALCSIZE, sent|wparam, 0 },
743 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
744 { WM_CREATE, sent },
745 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
746 { WM_SIZE, sent|wparam, SIZE_RESTORED },
747 { WM_MOVE, sent },
748 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
749 { WM_SHOWWINDOW, sent|wparam, 1 },
750 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
751 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
752 { WM_ERASEBKGND, sent|parent|optional },
753 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
754 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
755 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
756 { 0 }
758 /* ShowWindow(SW_SHOW) for a not visible child window */
759 static const struct message WmShowChildSeq[] = {
760 { WM_SHOWWINDOW, sent|wparam, 1 },
761 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
762 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
763 { WM_ERASEBKGND, sent|parent|optional },
764 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
765 { 0 }
767 /* ShowWindow(SW_HIDE) for a visible child window */
768 static const struct message WmHideChildSeq[] = {
769 { WM_SHOWWINDOW, sent|wparam, 0 },
770 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
771 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
772 { WM_ERASEBKGND, sent|parent|optional },
773 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
774 { 0 }
776 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
777 static const struct message WmHideChildSeq2[] = {
778 { WM_SHOWWINDOW, sent|wparam, 0 },
779 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
780 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
781 { WM_ERASEBKGND, sent|parent },
782 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
783 { 0 }
785 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
786 * for a not visible child window
788 static const struct message WmShowChildSeq_2[] = {
789 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
790 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
791 { WM_CHILDACTIVATE, sent },
792 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
793 { 0 }
795 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
796 * for a not visible child window
798 static const struct message WmShowChildSeq_3[] = {
799 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
800 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
801 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
802 { 0 }
804 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
805 * for a visible child window with a caption
807 static const struct message WmShowChildSeq_4[] = {
808 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
809 { WM_CHILDACTIVATE, sent },
810 { 0 }
812 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
813 static const struct message WmShowChildInvisibleParentSeq_1[] = {
814 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
815 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
816 { WM_NCCALCSIZE, sent|wparam, 1 },
817 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
818 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
819 { WM_MOVE, sent|defwinproc },
820 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
821 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
822 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
823 /* FIXME: Wine creates an icon/title window while Windows doesn't */
824 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
825 { WM_GETTEXT, sent|optional },
826 { 0 }
828 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
829 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
830 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
831 { 0 }
833 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
834 static const struct message WmShowChildInvisibleParentSeq_2[] = {
835 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
836 { WM_GETMINMAXINFO, sent },
837 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
838 { WM_NCCALCSIZE, sent|wparam, 1 },
839 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
840 { WM_CHILDACTIVATE, sent },
841 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
842 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
843 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
844 { 0 }
846 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
847 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
848 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
849 { 0 }
851 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
852 static const struct message WmShowChildInvisibleParentSeq_3[] = {
853 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
854 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
855 { WM_NCCALCSIZE, sent|wparam, 1 },
856 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
857 { WM_CHILDACTIVATE, sent },
858 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
859 { WM_MOVE, sent|defwinproc },
860 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
861 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
862 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
863 /* FIXME: Wine creates an icon/title window while Windows doesn't */
864 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
865 { WM_GETTEXT, sent|optional },
866 { 0 }
868 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
869 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
870 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
871 { 0 }
873 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
874 static const struct message WmShowChildInvisibleParentSeq_4[] = {
875 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
876 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
877 { WM_NCCALCSIZE, sent|wparam, 1 },
878 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
879 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
880 { WM_MOVE, sent|defwinproc },
881 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
882 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
883 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
884 /* FIXME: Wine creates an icon/title window while Windows doesn't */
885 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
886 { WM_GETTEXT, sent|optional },
887 { 0 }
889 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
890 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
891 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
892 { 0 }
894 /* ShowWindow(SW_SHOW) for child with invisible parent */
895 static const struct message WmShowChildInvisibleParentSeq_5[] = {
896 { WM_SHOWWINDOW, sent|wparam, 1 },
897 { 0 }
899 /* ShowWindow(SW_HIDE) for child with invisible parent */
900 static const struct message WmHideChildInvisibleParentSeq[] = {
901 { WM_SHOWWINDOW, sent|wparam, 0 },
902 { 0 }
904 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
905 static const struct message WmShowChildInvisibleParentSeq_6[] = {
906 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
907 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
908 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
909 { 0 }
911 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
912 static const struct message WmHideChildInvisibleParentSeq_2[] = {
913 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
914 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
915 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
916 { 0 }
918 /* DestroyWindow for a visible child window */
919 static const struct message WmDestroyChildSeq[] = {
920 { HCBT_DESTROYWND, hook },
921 { 0x0090, sent|optional },
922 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
923 { WM_SHOWWINDOW, sent|wparam, 0 },
924 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
925 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
926 { WM_ERASEBKGND, sent|parent|optional },
927 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
928 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
929 { WM_KILLFOCUS, sent },
930 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
931 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
932 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
933 { WM_SETFOCUS, sent|parent },
934 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
935 { WM_DESTROY, sent },
936 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
937 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
938 { WM_NCDESTROY, sent },
939 { 0 }
941 /* DestroyWindow for a visible child window with invisible parent */
942 static const struct message WmDestroyInvisibleChildSeq[] = {
943 { HCBT_DESTROYWND, hook },
944 { 0x0090, sent|optional },
945 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
946 { WM_SHOWWINDOW, sent|wparam, 0 },
947 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
948 { WM_DESTROY, sent },
949 { WM_NCDESTROY, sent },
950 { 0 }
952 /* Moving the mouse in nonclient area */
953 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
954 { WM_NCHITTEST, sent },
955 { WM_SETCURSOR, sent },
956 { WM_NCMOUSEMOVE, posted },
957 { 0 }
959 /* Moving the mouse in client area */
960 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
961 { WM_NCHITTEST, sent },
962 { WM_SETCURSOR, sent },
963 { WM_MOUSEMOVE, posted },
964 { 0 }
966 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
967 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
968 { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
969 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
970 { WM_GETMINMAXINFO, sent|defwinproc },
971 { WM_ENTERSIZEMOVE, sent|defwinproc },
972 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
973 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
974 { WM_MOVE, sent|defwinproc },
975 { WM_EXITSIZEMOVE, sent|defwinproc },
976 { 0 }
978 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
979 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
980 { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
981 { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
982 { WM_GETMINMAXINFO, sent|defwinproc },
983 { WM_ENTERSIZEMOVE, sent|defwinproc },
984 { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
985 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
986 { WM_GETMINMAXINFO, sent|defwinproc },
987 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
988 { WM_NCPAINT, sent|defwinproc|wparam, 1 },
989 { WM_GETTEXT, sent|defwinproc },
990 { WM_ERASEBKGND, sent|defwinproc },
991 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
992 { WM_MOVE, sent|defwinproc },
993 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
994 { WM_EXITSIZEMOVE, sent|defwinproc },
995 { 0 }
997 /* Resizing child window with MoveWindow (32) */
998 static const struct message WmResizingChildWithMoveWindowSeq[] = {
999 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1000 { WM_NCCALCSIZE, sent|wparam, 1 },
1001 { WM_ERASEBKGND, sent|parent|optional },
1002 { WM_ERASEBKGND, sent|optional },
1003 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1004 { WM_MOVE, sent|defwinproc },
1005 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1006 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1007 { 0 }
1009 /* Clicking on inactive button */
1010 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1011 { WM_NCHITTEST, sent },
1012 { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1013 { WM_MOUSEACTIVATE, sent },
1014 { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1015 { WM_SETCURSOR, sent },
1016 { WM_SETCURSOR, sent|parent|defwinproc },
1017 { WM_LBUTTONDOWN, posted },
1018 { WM_KILLFOCUS, posted|parent },
1019 { WM_SETFOCUS, posted },
1020 { WM_CTLCOLORBTN, posted|parent },
1021 { BM_SETSTATE, posted },
1022 { WM_CTLCOLORBTN, posted|parent },
1023 { WM_LBUTTONUP, posted },
1024 { BM_SETSTATE, posted },
1025 { WM_CTLCOLORBTN, posted|parent },
1026 { WM_COMMAND, posted|parent },
1027 { 0 }
1029 /* Reparenting a button (16/32) */
1030 /* The last child (button) reparented gets topmost for its new parent. */
1031 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1032 { WM_SHOWWINDOW, sent|wparam, 0 },
1033 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1034 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1035 { WM_ERASEBKGND, sent|parent },
1036 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1037 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1038 { WM_CHILDACTIVATE, sent },
1039 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1040 { WM_MOVE, sent|defwinproc },
1041 { WM_SHOWWINDOW, sent|wparam, 1 },
1042 { 0 }
1044 /* Creation of a custom dialog (32) */
1045 static const struct message WmCreateCustomDialogSeq[] = {
1046 { HCBT_CREATEWND, hook },
1047 { WM_GETMINMAXINFO, sent },
1048 { WM_NCCREATE, sent },
1049 { WM_NCCALCSIZE, sent|wparam, 0 },
1050 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1051 { WM_CREATE, sent },
1052 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1053 { WM_SHOWWINDOW, sent|wparam, 1 },
1054 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1055 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1056 { HCBT_ACTIVATE, hook },
1057 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1060 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1062 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1064 { WM_NCACTIVATE, sent|wparam, 1 },
1065 { WM_GETTEXT, sent|optional|defwinproc },
1066 { WM_GETTEXT, sent|optional|defwinproc },
1067 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1068 { WM_ACTIVATE, sent|wparam, 1 },
1069 { WM_KILLFOCUS, sent|parent },
1070 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1071 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1072 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1073 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1074 { WM_SETFOCUS, sent },
1075 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1076 { WM_NCPAINT, sent|wparam, 1 },
1077 { WM_GETTEXT, sent|optional|defwinproc },
1078 { WM_GETTEXT, sent|optional|defwinproc },
1079 { WM_ERASEBKGND, sent },
1080 { WM_CTLCOLORDLG, sent|defwinproc },
1081 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1082 { WM_GETTEXT, sent|optional },
1083 { WM_GETTEXT, sent|optional },
1084 { WM_NCCALCSIZE, sent|optional },
1085 { WM_NCPAINT, sent|optional },
1086 { WM_GETTEXT, sent|optional|defwinproc },
1087 { WM_GETTEXT, sent|optional|defwinproc },
1088 { WM_ERASEBKGND, sent|optional },
1089 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1090 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1091 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1092 { WM_MOVE, sent },
1093 { 0 }
1095 /* Calling EndDialog for a custom dialog (32) */
1096 static const struct message WmEndCustomDialogSeq[] = {
1097 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1098 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1099 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1100 { WM_GETTEXT, sent|optional },
1101 { HCBT_ACTIVATE, hook },
1102 { WM_NCACTIVATE, sent|wparam, 0 },
1103 { WM_GETTEXT, sent|optional|defwinproc },
1104 { WM_GETTEXT, sent|optional|defwinproc },
1105 { WM_ACTIVATE, sent|wparam, 0 },
1106 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1107 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1108 { HCBT_SETFOCUS, hook },
1109 { WM_KILLFOCUS, sent },
1110 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1111 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1112 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1113 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1114 { WM_SETFOCUS, sent|parent|defwinproc },
1115 { 0 }
1117 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1118 static const struct message WmShowCustomDialogSeq[] = {
1119 { WM_SHOWWINDOW, sent|wparam, 1 },
1120 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1121 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1122 { HCBT_ACTIVATE, hook },
1123 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1125 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1127 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1128 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1129 { WM_NCACTIVATE, sent|wparam, 1 },
1130 { WM_ACTIVATE, sent|wparam, 1 },
1132 { WM_KILLFOCUS, sent|parent },
1133 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1134 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1135 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1136 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1137 { WM_SETFOCUS, sent },
1138 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1139 { WM_NCPAINT, sent|wparam, 1 },
1140 { WM_ERASEBKGND, sent },
1141 { WM_CTLCOLORDLG, sent|defwinproc },
1142 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1143 { 0 }
1145 /* Creation and destruction of a modal dialog (32) */
1146 static const struct message WmModalDialogSeq[] = {
1147 { WM_CANCELMODE, sent|parent },
1148 { HCBT_SETFOCUS, hook },
1149 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1150 { WM_KILLFOCUS, sent|parent },
1151 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1152 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1153 { WM_ENABLE, sent|parent|wparam, 0 },
1154 { HCBT_CREATEWND, hook },
1155 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1156 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1157 { WM_SETFONT, sent },
1158 { WM_INITDIALOG, sent },
1159 { WM_CHANGEUISTATE, sent|optional },
1160 { WM_UPDATEUISTATE, sent|optional },
1161 { WM_SHOWWINDOW, sent },
1162 { HCBT_ACTIVATE, hook },
1163 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1164 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1165 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1166 { WM_NCACTIVATE, sent|wparam, 1 },
1167 { WM_GETTEXT, sent|optional },
1168 { WM_ACTIVATE, sent|wparam, 1 },
1169 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1170 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1171 { WM_NCPAINT, sent },
1172 { WM_GETTEXT, sent|optional },
1173 { WM_ERASEBKGND, sent },
1174 { WM_CTLCOLORDLG, sent },
1175 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1176 { WM_GETTEXT, sent|optional },
1177 { WM_NCCALCSIZE, sent|optional },
1178 { WM_NCPAINT, sent|optional },
1179 { WM_GETTEXT, sent|optional },
1180 { WM_ERASEBKGND, sent|optional },
1181 { WM_CTLCOLORDLG, sent|optional },
1182 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1183 { WM_PAINT, sent|optional },
1184 { WM_CTLCOLORBTN, sent },
1185 { WM_ENTERIDLE, sent|parent|optional },
1186 { WM_ENTERIDLE, sent|parent|optional },
1187 { WM_ENTERIDLE, sent|parent|optional },
1188 { WM_ENTERIDLE, sent|parent|optional },
1189 { WM_ENTERIDLE, sent|parent|optional },
1190 { WM_ENTERIDLE, sent|parent|optional },
1191 { WM_ENTERIDLE, sent|parent|optional },
1192 { WM_ENTERIDLE, sent|parent|optional },
1193 { WM_ENTERIDLE, sent|parent|optional },
1194 { WM_ENTERIDLE, sent|parent|optional },
1195 { WM_ENTERIDLE, sent|parent|optional },
1196 { WM_ENTERIDLE, sent|parent|optional },
1197 { WM_ENTERIDLE, sent|parent|optional },
1198 { WM_ENTERIDLE, sent|parent|optional },
1199 { WM_ENTERIDLE, sent|parent|optional },
1200 { WM_ENTERIDLE, sent|parent|optional },
1201 { WM_ENTERIDLE, sent|parent|optional },
1202 { WM_ENTERIDLE, sent|parent|optional },
1203 { WM_ENTERIDLE, sent|parent|optional },
1204 { WM_ENTERIDLE, sent|parent|optional },
1205 { WM_TIMER, sent },
1206 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1207 { WM_ENABLE, sent|parent|wparam, 1 },
1208 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1209 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1210 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1211 { WM_GETTEXT, sent|optional },
1212 { HCBT_ACTIVATE, hook },
1213 { WM_NCACTIVATE, sent|wparam, 0 },
1214 { WM_GETTEXT, sent|optional },
1215 { WM_ACTIVATE, sent|wparam, 0 },
1216 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1217 { WM_WINDOWPOSCHANGING, sent|optional },
1218 { HCBT_SETFOCUS, hook },
1219 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1220 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1221 { WM_SETFOCUS, sent|parent|defwinproc },
1222 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1223 { HCBT_DESTROYWND, hook },
1224 { 0x0090, sent|optional },
1225 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1226 { WM_DESTROY, sent },
1227 { WM_NCDESTROY, sent },
1228 { 0 }
1230 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1231 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1232 /* (inside dialog proc, handling WM_INITDIALOG) */
1233 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1234 { WM_NCCALCSIZE, sent },
1235 { WM_NCACTIVATE, sent|parent|wparam, 0 },
1236 { WM_GETTEXT, sent|defwinproc },
1237 { WM_ACTIVATE, sent|parent|wparam, 0 },
1238 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1239 { WM_WINDOWPOSCHANGING, sent|parent },
1240 { WM_NCACTIVATE, sent|wparam, 1 },
1241 { WM_ACTIVATE, sent|wparam, 1 },
1242 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1243 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1244 /* (setting focus) */
1245 { WM_SHOWWINDOW, sent|wparam, 1 },
1246 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1247 { WM_NCPAINT, sent },
1248 { WM_GETTEXT, sent|defwinproc },
1249 { WM_ERASEBKGND, sent },
1250 { WM_CTLCOLORDLG, sent|defwinproc },
1251 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1252 { WM_PAINT, sent },
1253 /* (bunch of WM_CTLCOLOR* for each control) */
1254 { WM_PAINT, sent|parent },
1255 { WM_ENTERIDLE, sent|parent|wparam, 0 },
1256 { WM_SETCURSOR, sent|parent },
1257 { 0 }
1259 /* SetMenu for NonVisible windows with size change*/
1260 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1261 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1262 { WM_NCCALCSIZE, sent|wparam, 1 },
1263 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1264 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1265 { WM_MOVE, sent|defwinproc },
1266 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1267 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1268 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1269 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1270 { WM_GETTEXT, sent|optional },
1271 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1272 { 0 }
1274 /* SetMenu for NonVisible windows with no size change */
1275 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1276 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1277 { WM_NCCALCSIZE, sent|wparam, 1 },
1278 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1279 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1280 { 0 }
1282 /* SetMenu for Visible windows with size change */
1283 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1284 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1285 { WM_NCCALCSIZE, sent|wparam, 1 },
1286 { 0x0093, sent|defwinproc|optional },
1287 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1288 { WM_NCPAINT, sent }, /* wparam != 1 */
1289 { 0x0093, sent|defwinproc|optional },
1290 { 0x0093, sent|defwinproc|optional },
1291 { 0x0091, sent|defwinproc|optional },
1292 { 0x0092, sent|defwinproc|optional },
1293 { WM_GETTEXT, sent|defwinproc|optional },
1294 { WM_ERASEBKGND, sent|optional },
1295 { WM_ACTIVATE, sent|optional },
1296 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1297 { WM_MOVE, sent|defwinproc },
1298 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1299 { 0x0093, sent|optional },
1300 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1301 { 0x0093, sent|defwinproc|optional },
1302 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1303 { 0x0093, sent|defwinproc|optional },
1304 { 0x0093, sent|defwinproc|optional },
1305 { 0x0091, sent|defwinproc|optional },
1306 { 0x0092, sent|defwinproc|optional },
1307 { WM_ERASEBKGND, sent|optional },
1308 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1309 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1310 { 0 }
1312 /* SetMenu for Visible windows with no size change */
1313 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1314 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1315 { WM_NCCALCSIZE, sent|wparam, 1 },
1316 { WM_NCPAINT, sent }, /* wparam != 1 */
1317 { WM_GETTEXT, sent|defwinproc|optional },
1318 { WM_ERASEBKGND, sent|optional },
1319 { WM_ACTIVATE, sent|optional },
1320 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1321 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1322 { 0 }
1324 /* DrawMenuBar for a visible window */
1325 static const struct message WmDrawMenuBarSeq[] =
1327 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1328 { WM_NCCALCSIZE, sent|wparam, 1 },
1329 { 0x0093, sent|defwinproc|optional },
1330 { WM_NCPAINT, sent }, /* wparam != 1 */
1331 { 0x0093, sent|defwinproc|optional },
1332 { 0x0093, sent|defwinproc|optional },
1333 { 0x0091, sent|defwinproc|optional },
1334 { 0x0092, sent|defwinproc|optional },
1335 { WM_GETTEXT, sent|defwinproc|optional },
1336 { WM_ERASEBKGND, sent|optional },
1337 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1338 { 0x0093, sent|optional },
1339 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1340 { 0 }
1343 static const struct message WmSetRedrawFalseSeq[] =
1345 { WM_SETREDRAW, sent|wparam, 0 },
1346 { 0 }
1349 static const struct message WmSetRedrawTrueSeq[] =
1351 { WM_SETREDRAW, sent|wparam, 1 },
1352 { 0 }
1355 static const struct message WmEnableWindowSeq_1[] =
1357 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1358 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1359 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1360 { 0 }
1363 static const struct message WmEnableWindowSeq_2[] =
1365 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1366 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1367 { 0 }
1370 static const struct message WmGetScrollRangeSeq[] =
1372 { SBM_GETRANGE, sent },
1373 { 0 }
1375 static const struct message WmGetScrollInfoSeq[] =
1377 { SBM_GETSCROLLINFO, sent },
1378 { 0 }
1380 static const struct message WmSetScrollRangeSeq[] =
1382 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1383 sends SBM_SETSCROLLINFO.
1385 { SBM_SETSCROLLINFO, sent },
1386 { 0 }
1388 /* SetScrollRange for a window without a non-client area */
1389 static const struct message WmSetScrollRangeHSeq_empty[] =
1391 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1392 { 0 }
1394 static const struct message WmSetScrollRangeVSeq_empty[] =
1396 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1397 { 0 }
1399 static const struct message WmSetScrollRangeHVSeq[] =
1401 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1402 { WM_NCCALCSIZE, sent|wparam, 1 },
1403 { WM_GETTEXT, sent|defwinproc|optional },
1404 { WM_ERASEBKGND, sent|optional },
1405 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1406 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1407 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1408 { 0 }
1410 /* SetScrollRange for a window with a non-client area */
1411 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1413 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1414 { WM_NCCALCSIZE, sent|wparam, 1 },
1415 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1416 { WM_NCPAINT, sent|optional },
1417 { WM_STYLECHANGING, sent|defwinproc|optional },
1418 { WM_STYLECHANGED, sent|defwinproc|optional },
1419 { WM_STYLECHANGING, sent|defwinproc|optional },
1420 { WM_STYLECHANGED, sent|defwinproc|optional },
1421 { WM_STYLECHANGING, sent|defwinproc|optional },
1422 { WM_STYLECHANGED, sent|defwinproc|optional },
1423 { WM_STYLECHANGING, sent|defwinproc|optional },
1424 { WM_STYLECHANGED, sent|defwinproc|optional },
1425 { WM_GETTEXT, sent|defwinproc|optional },
1426 { WM_GETTEXT, sent|defwinproc|optional },
1427 { WM_ERASEBKGND, sent|optional },
1428 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1429 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1430 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1431 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1432 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1433 { WM_GETTEXT, sent|optional },
1434 { WM_GETTEXT, sent|optional },
1435 { WM_GETTEXT, sent|optional },
1436 { WM_GETTEXT, sent|optional },
1437 { 0 }
1439 /* test if we receive the right sequence of messages */
1440 /* after calling ShowWindow( SW_SHOWNA) */
1441 static const struct message WmSHOWNAChildInvisParInvis[] = {
1442 { WM_SHOWWINDOW, sent|wparam, 1 },
1443 { 0 }
1445 static const struct message WmSHOWNAChildVisParInvis[] = {
1446 { WM_SHOWWINDOW, sent|wparam, 1 },
1447 { 0 }
1449 static const struct message WmSHOWNAChildVisParVis[] = {
1450 { WM_SHOWWINDOW, sent|wparam, 1 },
1451 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1452 { 0 }
1454 static const struct message WmSHOWNAChildInvisParVis[] = {
1455 { WM_SHOWWINDOW, sent|wparam, 1 },
1456 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1457 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1458 { WM_ERASEBKGND, sent|optional },
1459 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1460 { 0 }
1462 static const struct message WmSHOWNATopVisible[] = {
1463 { WM_SHOWWINDOW, sent|wparam, 1 },
1464 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1465 { 0 }
1467 static const struct message WmSHOWNATopInvisible[] = {
1468 { WM_SHOWWINDOW, sent|wparam, 1 },
1469 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1470 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1471 { WM_NCPAINT, sent|wparam, 1 },
1472 { WM_GETTEXT, sent|defwinproc|optional },
1473 { WM_ERASEBKGND, sent|optional },
1474 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1475 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1476 { WM_NCPAINT, sent|wparam|optional, 1 },
1477 { WM_ERASEBKGND, sent|optional },
1478 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1479 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1480 { WM_MOVE, sent },
1481 { 0 }
1484 static int after_end_dialog, test_def_id;
1485 static int sequence_cnt, sequence_size;
1486 static struct message* sequence;
1487 static int log_all_parent_messages;
1489 /* user32 functions */
1490 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1491 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1492 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1493 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1494 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1495 /* kernel32 functions */
1496 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1498 static void init_procs(void)
1500 HMODULE user32 = GetModuleHandleA("user32.dll");
1501 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1503 #define GET_PROC(dll, func) \
1504 p ## func = (void*)GetProcAddress(dll, #func); \
1505 if(!p ## func) { \
1506 trace("GetProcAddress(%s) failed\n", #func); \
1509 GET_PROC(user32, GetAncestor)
1510 GET_PROC(user32, NotifyWinEvent)
1511 GET_PROC(user32, SetWinEventHook)
1512 GET_PROC(user32, TrackMouseEvent)
1513 GET_PROC(user32, UnhookWinEvent)
1515 GET_PROC(kernel32, GetCPInfoExA)
1517 #undef GET_PROC
1520 static void add_message(const struct message *msg)
1522 if (!sequence)
1524 sequence_size = 10;
1525 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1527 if (sequence_cnt == sequence_size)
1529 sequence_size *= 2;
1530 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1532 assert(sequence);
1534 sequence[sequence_cnt].message = msg->message;
1535 sequence[sequence_cnt].flags = msg->flags;
1536 sequence[sequence_cnt].wParam = msg->wParam;
1537 sequence[sequence_cnt].lParam = msg->lParam;
1539 sequence_cnt++;
1542 /* try to make sure pending X events have been processed before continuing */
1543 static void flush_events(void)
1545 MSG msg;
1546 int diff = 200;
1547 int min_timeout = 50;
1548 DWORD time = GetTickCount() + diff;
1550 while (diff > 0)
1552 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1553 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1554 diff = time - GetTickCount();
1555 min_timeout = 10;
1559 static void flush_sequence(void)
1561 HeapFree(GetProcessHeap(), 0, sequence);
1562 sequence = 0;
1563 sequence_cnt = sequence_size = 0;
1566 #define ok_sequence( exp, contx, todo) \
1567 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1570 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1571 const char *file, int line)
1573 static const struct message end_of_sequence = { 0, 0, 0, 0 };
1574 const struct message *actual;
1575 int failcount = 0;
1577 add_message(&end_of_sequence);
1579 actual = sequence;
1581 while (expected->message && actual->message)
1583 trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1585 if (expected->message == actual->message)
1587 if (expected->flags & wparam)
1589 if (expected->wParam != actual->wParam && todo)
1591 todo_wine {
1592 failcount ++;
1593 ok_( file, line) (FALSE,
1594 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1595 context, expected->message, expected->wParam, actual->wParam);
1598 else
1599 ok_( file, line) (expected->wParam == actual->wParam,
1600 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1601 context, expected->message, expected->wParam, actual->wParam);
1603 if (expected->flags & lparam)
1605 if (expected->lParam != actual->lParam && todo)
1607 todo_wine {
1608 failcount ++;
1609 ok_( file, line) (FALSE,
1610 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1611 context, expected->message, expected->lParam, actual->lParam);
1614 else
1615 ok_( file, line) (expected->lParam == actual->lParam,
1616 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1617 context, expected->message, expected->lParam, actual->lParam);
1619 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1621 todo_wine {
1622 failcount ++;
1623 ok_( file, line) (FALSE,
1624 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1625 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1628 else
1629 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1630 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1631 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1632 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1633 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1634 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1635 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1636 "%s: the msg 0x%04x should have been %s\n",
1637 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1638 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1639 "%s: the msg 0x%04x was expected in %s\n",
1640 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1641 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1642 "%s: the msg 0x%04x should have been sent by a hook\n",
1643 context, expected->message);
1644 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1645 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1646 context, expected->message);
1647 expected++;
1648 actual++;
1650 /* silently drop winevent messages if there is no support for them */
1651 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1652 expected++;
1653 else if (todo)
1655 failcount++;
1656 todo_wine {
1657 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1658 context, expected->message, actual->message);
1660 flush_sequence();
1661 return;
1663 else
1665 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1666 context, expected->message, actual->message);
1667 expected++;
1668 actual++;
1672 /* skip all optional trailing messages */
1673 while (expected->message && ((expected->flags & optional) ||
1674 ((expected->flags & winevent_hook) && !hEvent_hook)))
1675 expected++;
1677 if (todo)
1679 todo_wine {
1680 if (expected->message || actual->message) {
1681 failcount++;
1682 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1683 context, expected->message, actual->message);
1687 else
1689 if (expected->message || actual->message)
1690 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1691 context, expected->message, actual->message);
1693 if( todo && !failcount) /* succeeded yet marked todo */
1694 todo_wine {
1695 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1698 flush_sequence();
1701 /******************************** MDI test **********************************/
1703 /* CreateWindow for MDI frame window, initially visible */
1704 static const struct message WmCreateMDIframeSeq[] = {
1705 { HCBT_CREATEWND, hook },
1706 { WM_GETMINMAXINFO, sent },
1707 { WM_NCCREATE, sent },
1708 { WM_NCCALCSIZE, sent|wparam, 0 },
1709 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1710 { WM_CREATE, sent },
1711 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1712 { WM_SHOWWINDOW, sent|wparam, 1 },
1713 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1714 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1715 { HCBT_ACTIVATE, hook },
1716 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1717 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1718 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1719 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1720 { WM_NCACTIVATE, sent|wparam, 1 },
1721 { WM_GETTEXT, sent|defwinproc|optional },
1722 { WM_ACTIVATE, sent|wparam, 1 },
1723 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1724 { HCBT_SETFOCUS, hook },
1725 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1726 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1727 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1728 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1729 /* Win9x adds SWP_NOZORDER below */
1730 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1731 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1732 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1733 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1734 { WM_MOVE, sent },
1735 { 0 }
1737 /* DestroyWindow for MDI frame window, initially visible */
1738 static const struct message WmDestroyMDIframeSeq[] = {
1739 { HCBT_DESTROYWND, hook },
1740 { 0x0090, sent|optional },
1741 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1742 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1743 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1744 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1745 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1746 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1747 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1748 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1749 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1750 { WM_DESTROY, sent },
1751 { WM_NCDESTROY, sent },
1752 { 0 }
1754 /* CreateWindow for MDI client window, initially visible */
1755 static const struct message WmCreateMDIclientSeq[] = {
1756 { HCBT_CREATEWND, hook },
1757 { WM_NCCREATE, sent },
1758 { WM_NCCALCSIZE, sent|wparam, 0 },
1759 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1760 { WM_CREATE, sent },
1761 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1762 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1763 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1764 { WM_MOVE, sent },
1765 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1766 { WM_SHOWWINDOW, sent|wparam, 1 },
1767 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1768 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1769 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1770 { 0 }
1772 /* ShowWindow(SW_SHOW) for MDI client window */
1773 static const struct message WmShowMDIclientSeq[] = {
1774 { WM_SHOWWINDOW, sent|wparam, 1 },
1775 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1776 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1777 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1778 { 0 }
1780 /* ShowWindow(SW_HIDE) for MDI client window */
1781 static const struct message WmHideMDIclientSeq[] = {
1782 { WM_SHOWWINDOW, sent|wparam, 0 },
1783 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1784 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1785 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1786 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1787 { 0 }
1789 /* DestroyWindow for MDI client window, initially visible */
1790 static const struct message WmDestroyMDIclientSeq[] = {
1791 { HCBT_DESTROYWND, hook },
1792 { 0x0090, sent|optional },
1793 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1794 { WM_SHOWWINDOW, sent|wparam, 0 },
1795 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1796 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1797 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1798 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1799 { WM_DESTROY, sent },
1800 { WM_NCDESTROY, sent },
1801 { 0 }
1803 /* CreateWindow for MDI child window, initially visible */
1804 static const struct message WmCreateMDIchildVisibleSeq[] = {
1805 { HCBT_CREATEWND, hook },
1806 { WM_NCCREATE, sent },
1807 { WM_NCCALCSIZE, sent|wparam, 0 },
1808 { WM_CREATE, sent },
1809 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1810 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1811 { WM_MOVE, sent },
1812 /* Win2k sends wparam set to
1813 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1814 * while Win9x doesn't bother to set child window id according to
1815 * CLIENTCREATESTRUCT.idFirstChild
1817 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1818 { WM_SHOWWINDOW, sent|wparam, 1 },
1819 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1820 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1821 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1822 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1823 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1824 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1825 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1827 /* Win9x: message sequence terminates here. */
1829 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1830 { HCBT_SETFOCUS, hook }, /* in MDI client */
1831 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1832 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1833 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1834 { WM_SETFOCUS, sent }, /* in MDI client */
1835 { HCBT_SETFOCUS, hook },
1836 { WM_KILLFOCUS, sent }, /* in MDI client */
1837 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1838 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1839 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1840 { WM_SETFOCUS, sent|defwinproc },
1841 { WM_MDIACTIVATE, sent|defwinproc },
1842 { 0 }
1844 /* CreateWindow for MDI child window with invisible parent */
1845 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
1846 { HCBT_CREATEWND, hook },
1847 { WM_GETMINMAXINFO, sent },
1848 { WM_NCCREATE, sent },
1849 { WM_NCCALCSIZE, sent|wparam, 0 },
1850 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1851 { WM_CREATE, sent },
1852 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1853 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1854 { WM_MOVE, sent },
1855 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1856 { WM_SHOWWINDOW, sent|wparam, 1 },
1857 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1858 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1859 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1860 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1862 /* Win9x: message sequence terminates here. */
1864 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1865 { HCBT_SETFOCUS, hook }, /* in MDI client */
1866 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1867 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1868 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1869 { WM_SETFOCUS, sent }, /* in MDI client */
1870 { HCBT_SETFOCUS, hook },
1871 { WM_KILLFOCUS, sent }, /* in MDI client */
1872 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1873 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1874 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1875 { WM_SETFOCUS, sent|defwinproc },
1876 { WM_MDIACTIVATE, sent|defwinproc },
1877 { 0 }
1879 /* DestroyWindow for MDI child window, initially visible */
1880 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1881 { HCBT_DESTROYWND, hook },
1882 /* Win2k sends wparam set to
1883 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1884 * while Win9x doesn't bother to set child window id according to
1885 * CLIENTCREATESTRUCT.idFirstChild
1887 { 0x0090, sent|optional },
1888 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1889 { WM_SHOWWINDOW, sent|wparam, 0 },
1890 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1891 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1892 { WM_ERASEBKGND, sent|parent|optional },
1893 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1895 /* { WM_DESTROY, sent }
1896 * Win9x: message sequence terminates here.
1899 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1900 { WM_KILLFOCUS, sent },
1901 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1902 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1903 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1904 { WM_SETFOCUS, sent }, /* in MDI client */
1906 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1907 { WM_KILLFOCUS, sent }, /* in MDI client */
1908 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1909 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1910 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1911 { WM_SETFOCUS, sent }, /* in MDI client */
1913 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1915 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1916 { WM_KILLFOCUS, sent },
1917 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1918 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1919 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1920 { WM_SETFOCUS, sent }, /* in MDI client */
1922 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1923 { WM_KILLFOCUS, sent }, /* in MDI client */
1924 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1925 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1926 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1927 { WM_SETFOCUS, sent }, /* in MDI client */
1929 { WM_DESTROY, sent },
1931 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1932 { WM_KILLFOCUS, sent },
1933 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1934 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1935 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1936 { WM_SETFOCUS, sent }, /* in MDI client */
1938 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1939 { WM_KILLFOCUS, sent }, /* in MDI client */
1940 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1941 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1942 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1943 { WM_SETFOCUS, sent }, /* in MDI client */
1945 { WM_NCDESTROY, sent },
1946 { 0 }
1948 /* CreateWindow for MDI child window, initially invisible */
1949 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1950 { HCBT_CREATEWND, hook },
1951 { WM_NCCREATE, sent },
1952 { WM_NCCALCSIZE, sent|wparam, 0 },
1953 { WM_CREATE, sent },
1954 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1955 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1956 { WM_MOVE, sent },
1957 /* Win2k sends wparam set to
1958 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1959 * while Win9x doesn't bother to set child window id according to
1960 * CLIENTCREATESTRUCT.idFirstChild
1962 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1963 { 0 }
1965 /* DestroyWindow for MDI child window, initially invisible */
1966 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1967 { HCBT_DESTROYWND, hook },
1968 /* Win2k sends wparam set to
1969 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1970 * while Win9x doesn't bother to set child window id according to
1971 * CLIENTCREATESTRUCT.idFirstChild
1973 { 0x0090, sent|optional },
1974 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1975 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1976 { WM_DESTROY, sent },
1977 { WM_NCDESTROY, sent },
1978 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
1979 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
1980 { 0 }
1982 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1983 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1984 { HCBT_CREATEWND, hook },
1985 { WM_NCCREATE, sent },
1986 { WM_NCCALCSIZE, sent|wparam, 0 },
1987 { WM_CREATE, sent },
1988 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1989 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1990 { WM_MOVE, sent },
1991 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1992 { WM_GETMINMAXINFO, sent },
1993 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1994 { WM_NCCALCSIZE, sent|wparam, 1 },
1995 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1996 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1997 /* in MDI frame */
1998 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1999 { WM_NCCALCSIZE, sent|wparam, 1 },
2000 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2001 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2002 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2003 /* Win2k sends wparam set to
2004 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2005 * while Win9x doesn't bother to set child window id according to
2006 * CLIENTCREATESTRUCT.idFirstChild
2008 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2009 { WM_SHOWWINDOW, sent|wparam, 1 },
2010 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2011 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2012 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2013 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2014 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2015 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2016 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2018 /* Win9x: message sequence terminates here. */
2020 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2021 { HCBT_SETFOCUS, hook }, /* in MDI client */
2022 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2023 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2024 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2025 { WM_SETFOCUS, sent }, /* in MDI client */
2026 { HCBT_SETFOCUS, hook },
2027 { WM_KILLFOCUS, sent }, /* in MDI client */
2028 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2029 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2030 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2031 { WM_SETFOCUS, sent|defwinproc },
2032 { WM_MDIACTIVATE, sent|defwinproc },
2033 /* in MDI frame */
2034 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2035 { WM_NCCALCSIZE, sent|wparam, 1 },
2036 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2037 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2038 { 0 }
2040 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2041 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2042 /* restore the 1st MDI child */
2043 { WM_SETREDRAW, sent|wparam, 0 },
2044 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2045 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2046 { WM_NCCALCSIZE, sent|wparam, 1 },
2047 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2048 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2049 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2050 /* in MDI frame */
2051 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2052 { WM_NCCALCSIZE, sent|wparam, 1 },
2053 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2054 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2055 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2056 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2057 /* create the 2nd MDI child */
2058 { HCBT_CREATEWND, hook },
2059 { WM_NCCREATE, sent },
2060 { WM_NCCALCSIZE, sent|wparam, 0 },
2061 { WM_CREATE, sent },
2062 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2063 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2064 { WM_MOVE, sent },
2065 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2066 { WM_GETMINMAXINFO, sent },
2067 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2068 { WM_NCCALCSIZE, sent|wparam, 1 },
2069 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2070 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2071 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2072 /* in MDI frame */
2073 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2074 { WM_NCCALCSIZE, sent|wparam, 1 },
2075 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2076 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2077 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2078 /* Win2k sends wparam set to
2079 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2080 * while Win9x doesn't bother to set child window id according to
2081 * CLIENTCREATESTRUCT.idFirstChild
2083 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2084 { WM_SHOWWINDOW, sent|wparam, 1 },
2085 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2086 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2087 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2088 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2089 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2090 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2092 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2093 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2095 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2097 /* Win9x: message sequence terminates here. */
2099 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2100 { HCBT_SETFOCUS, hook },
2101 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
2102 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2103 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2104 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2105 { WM_SETFOCUS, sent }, /* in MDI client */
2106 { HCBT_SETFOCUS, hook },
2107 { WM_KILLFOCUS, sent }, /* in MDI client */
2108 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2109 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2110 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2111 { WM_SETFOCUS, sent|defwinproc },
2113 { WM_MDIACTIVATE, sent|defwinproc },
2114 /* in MDI frame */
2115 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2116 { WM_NCCALCSIZE, sent|wparam, 1 },
2117 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2118 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2119 { 0 }
2121 /* WM_MDICREATE MDI child window, initially visible and maximized */
2122 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2123 { WM_MDICREATE, sent },
2124 { HCBT_CREATEWND, hook },
2125 { WM_NCCREATE, sent },
2126 { WM_NCCALCSIZE, sent|wparam, 0 },
2127 { WM_CREATE, sent },
2128 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2129 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2130 { WM_MOVE, sent },
2131 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2132 { WM_GETMINMAXINFO, sent },
2133 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2134 { WM_NCCALCSIZE, sent|wparam, 1 },
2135 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2136 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2138 /* in MDI frame */
2139 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2140 { WM_NCCALCSIZE, sent|wparam, 1 },
2141 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2142 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2143 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2145 /* Win2k sends wparam set to
2146 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2147 * while Win9x doesn't bother to set child window id according to
2148 * CLIENTCREATESTRUCT.idFirstChild
2150 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2151 { WM_SHOWWINDOW, sent|wparam, 1 },
2152 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2154 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2156 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2157 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2158 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2160 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2161 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2163 /* Win9x: message sequence terminates here. */
2165 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2166 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2167 { HCBT_SETFOCUS, hook }, /* in MDI client */
2168 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2169 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2170 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2171 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2172 { HCBT_SETFOCUS, hook|optional },
2173 { WM_KILLFOCUS, sent }, /* in MDI client */
2174 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2175 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2176 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2177 { WM_SETFOCUS, sent|defwinproc },
2179 { WM_MDIACTIVATE, sent|defwinproc },
2181 /* in MDI child */
2182 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2183 { WM_NCCALCSIZE, sent|wparam, 1 },
2184 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2185 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2187 /* in MDI frame */
2188 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2189 { WM_NCCALCSIZE, sent|wparam, 1 },
2190 { 0x0093, sent|defwinproc|optional },
2191 { 0x0093, sent|defwinproc|optional },
2192 { 0x0093, sent|defwinproc|optional },
2193 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2194 { WM_MOVE, sent|defwinproc },
2195 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2197 /* in MDI client */
2198 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2199 { WM_NCCALCSIZE, sent|wparam, 1 },
2200 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2201 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2203 /* in MDI child */
2204 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2205 { WM_NCCALCSIZE, sent|wparam, 1 },
2206 { 0x0093, sent|optional },
2207 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2208 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2210 { 0x0093, sent|optional },
2211 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2212 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2213 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2214 { 0x0093, sent|defwinproc|optional },
2215 { 0x0093, sent|defwinproc|optional },
2216 { 0x0093, sent|defwinproc|optional },
2217 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2218 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2220 { 0 }
2222 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2223 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2224 { HCBT_CREATEWND, hook },
2225 { WM_GETMINMAXINFO, sent },
2226 { WM_NCCREATE, sent },
2227 { WM_NCCALCSIZE, sent|wparam, 0 },
2228 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2229 { WM_CREATE, sent },
2230 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2231 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2232 { WM_MOVE, sent },
2233 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2234 { WM_GETMINMAXINFO, sent },
2235 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2236 { WM_GETMINMAXINFO, sent|defwinproc },
2237 { WM_NCCALCSIZE, sent|wparam, 1 },
2238 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|0x8000 },
2239 { WM_MOVE, sent|defwinproc },
2240 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2241 /* in MDI frame */
2242 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2243 { WM_NCCALCSIZE, sent|wparam, 1 },
2244 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2245 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2246 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2247 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2248 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2249 /* Win2k sends wparam set to
2250 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2251 * while Win9x doesn't bother to set child window id according to
2252 * CLIENTCREATESTRUCT.idFirstChild
2254 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2255 { 0 }
2257 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2258 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2259 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2260 { HCBT_SYSCOMMAND, hook },
2261 { WM_CLOSE, sent|defwinproc },
2262 { WM_MDIDESTROY, sent }, /* in MDI client */
2264 /* bring the 1st MDI child to top */
2265 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2266 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2268 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2270 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2271 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2272 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2274 /* maximize the 1st MDI child */
2275 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2276 { WM_GETMINMAXINFO, sent|defwinproc },
2277 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
2278 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2279 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2280 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2281 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2283 /* restore the 2nd MDI child */
2284 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2285 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2286 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2287 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2289 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2291 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2292 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2294 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2296 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2297 /* in MDI frame */
2298 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2299 { WM_NCCALCSIZE, sent|wparam, 1 },
2300 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2301 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2302 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2304 /* bring the 1st MDI child to top */
2305 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2306 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2307 { HCBT_SETFOCUS, hook },
2308 { WM_KILLFOCUS, sent|defwinproc },
2309 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2310 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2311 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2312 { WM_SETFOCUS, sent }, /* in MDI client */
2313 { HCBT_SETFOCUS, hook },
2314 { WM_KILLFOCUS, sent }, /* in MDI client */
2315 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2316 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2317 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2318 { WM_SETFOCUS, sent|defwinproc },
2319 { WM_MDIACTIVATE, sent|defwinproc },
2320 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2322 /* apparently ShowWindow(SW_SHOW) on an MDI client */
2323 { WM_SHOWWINDOW, sent|wparam, 1 },
2324 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2325 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2326 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2327 { WM_MDIREFRESHMENU, sent },
2329 { HCBT_DESTROYWND, hook },
2330 /* Win2k sends wparam set to
2331 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2332 * while Win9x doesn't bother to set child window id according to
2333 * CLIENTCREATESTRUCT.idFirstChild
2335 { 0x0090, sent|defwinproc|optional },
2336 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2337 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2338 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2339 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2340 { WM_ERASEBKGND, sent|parent|optional },
2341 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2343 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2344 { WM_DESTROY, sent|defwinproc },
2345 { WM_NCDESTROY, sent|defwinproc },
2346 { 0 }
2348 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2349 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2350 { WM_MDIDESTROY, sent }, /* in MDI client */
2351 { WM_SHOWWINDOW, sent|wparam, 0 },
2352 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2353 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2354 { WM_ERASEBKGND, sent|parent|optional },
2355 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2357 { HCBT_SETFOCUS, hook },
2358 { WM_KILLFOCUS, sent },
2359 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2360 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2361 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2362 { WM_SETFOCUS, sent }, /* in MDI client */
2363 { HCBT_SETFOCUS, hook },
2364 { WM_KILLFOCUS, sent }, /* in MDI client */
2365 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2366 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2367 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2368 { WM_SETFOCUS, sent },
2370 /* in MDI child */
2371 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2372 { WM_NCCALCSIZE, sent|wparam, 1 },
2373 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2374 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2376 /* in MDI frame */
2377 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2378 { WM_NCCALCSIZE, sent|wparam, 1 },
2379 { 0x0093, sent|defwinproc|optional },
2380 { 0x0093, sent|defwinproc|optional },
2381 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2382 { WM_MOVE, sent|defwinproc },
2383 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2385 /* in MDI client */
2386 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2387 { WM_NCCALCSIZE, sent|wparam, 1 },
2388 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2389 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2391 /* in MDI child */
2392 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2393 { WM_NCCALCSIZE, sent|wparam, 1 },
2394 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2395 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2397 /* in MDI child */
2398 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2399 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2400 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2401 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2403 /* in MDI frame */
2404 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2405 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2406 { 0x0093, sent|defwinproc|optional },
2407 { 0x0093, sent|defwinproc|optional },
2408 { 0x0093, sent|defwinproc|optional },
2409 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2410 { WM_MOVE, sent|defwinproc },
2411 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2413 /* in MDI client */
2414 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2415 { WM_NCCALCSIZE, sent|wparam, 1 },
2416 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2417 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2419 /* in MDI child */
2420 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2421 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2422 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2423 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2424 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2425 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2427 { 0x0093, sent|defwinproc|optional },
2428 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2429 { 0x0093, sent|defwinproc|optional },
2430 { 0x0093, sent|defwinproc|optional },
2431 { 0x0093, sent|defwinproc|optional },
2432 { 0x0093, sent|optional },
2434 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2435 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2436 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2437 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2438 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2440 /* in MDI frame */
2441 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2442 { WM_NCCALCSIZE, sent|wparam, 1 },
2443 { 0x0093, sent|defwinproc|optional },
2444 { 0x0093, sent|defwinproc|optional },
2445 { 0x0093, sent|defwinproc|optional },
2446 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2447 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2448 { 0x0093, sent|optional },
2450 { WM_NCACTIVATE, sent|wparam, 0 },
2451 { WM_MDIACTIVATE, sent },
2453 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2454 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2455 { WM_NCCALCSIZE, sent|wparam, 1 },
2457 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2459 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2460 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|0x8000 },
2461 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2463 /* in MDI child */
2464 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2465 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2466 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2467 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2469 /* in MDI frame */
2470 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2471 { WM_NCCALCSIZE, sent|wparam, 1 },
2472 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2473 { WM_MOVE, sent|defwinproc },
2474 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2476 /* in MDI client */
2477 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2478 { WM_NCCALCSIZE, sent|wparam, 1 },
2479 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2480 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2481 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2482 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2483 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2484 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2485 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2487 { HCBT_SETFOCUS, hook },
2488 { WM_KILLFOCUS, sent },
2489 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2490 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2491 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2492 { WM_SETFOCUS, sent }, /* in MDI client */
2494 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2496 { HCBT_DESTROYWND, hook },
2497 /* Win2k sends wparam set to
2498 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2499 * while Win9x doesn't bother to set child window id according to
2500 * CLIENTCREATESTRUCT.idFirstChild
2502 { 0x0090, sent|optional },
2503 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2505 { WM_SHOWWINDOW, sent|wparam, 0 },
2506 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2507 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2508 { WM_ERASEBKGND, sent|parent|optional },
2509 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2511 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2512 { WM_DESTROY, sent },
2513 { WM_NCDESTROY, sent },
2514 { 0 }
2516 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2517 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2518 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2519 { WM_GETMINMAXINFO, sent },
2520 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2521 { WM_NCCALCSIZE, sent|wparam, 1 },
2522 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2523 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2525 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2526 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2527 { HCBT_SETFOCUS, hook },
2528 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2529 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2530 { WM_SETFOCUS, sent }, /* in MDI client */
2531 { HCBT_SETFOCUS, hook },
2532 { WM_KILLFOCUS, sent }, /* in MDI client */
2533 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2534 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2535 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2536 { WM_SETFOCUS, sent|defwinproc },
2537 { WM_MDIACTIVATE, sent|defwinproc },
2538 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2539 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2540 /* in MDI frame */
2541 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2542 { WM_NCCALCSIZE, sent|wparam, 1 },
2543 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2544 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2545 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2546 { 0 }
2548 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2549 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2550 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2551 { WM_GETMINMAXINFO, sent },
2552 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2553 { WM_GETMINMAXINFO, sent|defwinproc },
2554 { WM_NCCALCSIZE, sent|wparam, 1 },
2555 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2556 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2558 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2559 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2560 { HCBT_SETFOCUS, hook },
2561 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2562 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2563 { WM_SETFOCUS, sent }, /* in MDI client */
2564 { HCBT_SETFOCUS, hook },
2565 { WM_KILLFOCUS, sent }, /* in MDI client */
2566 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2567 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2568 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2569 { WM_SETFOCUS, sent|defwinproc },
2570 { WM_MDIACTIVATE, sent|defwinproc },
2571 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2572 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2573 { 0 }
2575 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2576 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2577 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2578 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2579 { WM_GETMINMAXINFO, sent },
2580 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2581 { WM_GETMINMAXINFO, sent|defwinproc },
2582 { WM_NCCALCSIZE, sent|wparam, 1 },
2583 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2584 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2585 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
2586 { WM_MOVE, sent|defwinproc },
2587 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2589 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2590 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2591 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2592 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2593 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2594 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2595 /* in MDI frame */
2596 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2597 { WM_NCCALCSIZE, sent|wparam, 1 },
2598 { 0x0093, sent|defwinproc|optional },
2599 { 0x0094, sent|defwinproc|optional },
2600 { 0x0094, sent|defwinproc|optional },
2601 { 0x0094, sent|defwinproc|optional },
2602 { 0x0094, sent|defwinproc|optional },
2603 { 0x0093, sent|defwinproc|optional },
2604 { 0x0093, sent|defwinproc|optional },
2605 { 0x0091, sent|defwinproc|optional },
2606 { 0x0092, sent|defwinproc|optional },
2607 { 0x0092, sent|defwinproc|optional },
2608 { 0x0092, sent|defwinproc|optional },
2609 { 0x0092, sent|defwinproc|optional },
2610 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2611 { WM_MOVE, sent|defwinproc },
2612 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2613 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2614 /* in MDI client */
2615 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2616 { WM_NCCALCSIZE, sent|wparam, 1 },
2617 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2618 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2619 /* in MDI child */
2620 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2621 { WM_GETMINMAXINFO, sent|defwinproc },
2622 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2623 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2624 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2625 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2626 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2627 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2628 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2629 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2630 /* in MDI frame */
2631 { 0x0093, sent|optional },
2632 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2633 { 0x0093, sent|defwinproc|optional },
2634 { 0x0093, sent|defwinproc|optional },
2635 { 0x0093, sent|defwinproc|optional },
2636 { 0x0091, sent|defwinproc|optional },
2637 { 0x0092, sent|defwinproc|optional },
2638 { 0x0092, sent|defwinproc|optional },
2639 { 0x0092, sent|defwinproc|optional },
2640 { 0x0092, sent|defwinproc|optional },
2641 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2642 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2643 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2644 { 0 }
2646 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2647 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2648 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2649 { WM_GETMINMAXINFO, sent },
2650 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2651 { WM_NCCALCSIZE, sent|wparam, 1 },
2652 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2653 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2654 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2655 /* in MDI frame */
2656 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2657 { WM_NCCALCSIZE, sent|wparam, 1 },
2658 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2659 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2660 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2661 { 0 }
2663 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2664 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2665 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2666 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2667 { WM_NCCALCSIZE, sent|wparam, 1 },
2668 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2669 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2670 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2671 /* in MDI frame */
2672 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2673 { WM_NCCALCSIZE, sent|wparam, 1 },
2674 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2675 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2676 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2677 { 0 }
2679 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2680 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2681 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2682 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2683 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
2684 { WM_NCCALCSIZE, sent|wparam, 1 },
2685 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2686 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2687 { WM_MOVE, sent|defwinproc },
2688 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2689 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2690 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2691 { HCBT_SETFOCUS, hook },
2692 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2693 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2694 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2695 { WM_SETFOCUS, sent },
2696 { 0 }
2698 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2699 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2700 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2701 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
2702 { WM_NCCALCSIZE, sent|wparam, 1 },
2703 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2704 { WM_MOVE, sent|defwinproc },
2705 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2706 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2707 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2708 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2709 /* FIXME: Wine creates an icon/title window while Windows doesn't */
2710 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2711 { 0 }
2713 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2714 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2715 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2716 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2717 { WM_NCCALCSIZE, sent|wparam, 1 },
2718 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2719 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2720 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2721 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2722 /* in MDI frame */
2723 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2724 { WM_NCCALCSIZE, sent|wparam, 1 },
2725 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2726 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2727 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2728 { 0 }
2731 static HWND mdi_client;
2732 static WNDPROC old_mdi_client_proc;
2734 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2736 struct message msg;
2738 /* do not log painting messages */
2739 if (message != WM_PAINT &&
2740 message != WM_NCPAINT &&
2741 message != WM_SYNCPAINT &&
2742 message != WM_ERASEBKGND &&
2743 message != WM_NCPAINT &&
2744 message != WM_NCHITTEST &&
2745 message != WM_GETTEXT &&
2746 message != WM_MDIGETACTIVE &&
2747 message != WM_GETICON &&
2748 message != WM_DEVICECHANGE)
2750 trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2752 switch (message)
2754 case WM_WINDOWPOSCHANGING:
2755 case WM_WINDOWPOSCHANGED:
2757 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2759 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2760 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2761 winpos->hwnd, winpos->hwndInsertAfter,
2762 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2763 dump_winpos_flags(winpos->flags);
2765 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2766 * in the high word for internal purposes
2768 wParam = winpos->flags & 0xffff;
2769 /* We are not interested in the flags that don't match under XP and Win9x */
2770 wParam &= ~(SWP_NOZORDER);
2771 break;
2775 msg.message = message;
2776 msg.flags = sent|wparam|lparam;
2777 msg.wParam = wParam;
2778 msg.lParam = lParam;
2779 add_message(&msg);
2782 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2785 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2787 static long defwndproc_counter = 0;
2788 LRESULT ret;
2789 struct message msg;
2791 /* do not log painting messages */
2792 if (message != WM_PAINT &&
2793 message != WM_NCPAINT &&
2794 message != WM_SYNCPAINT &&
2795 message != WM_ERASEBKGND &&
2796 message != WM_NCPAINT &&
2797 message != WM_NCHITTEST &&
2798 message != WM_GETTEXT &&
2799 message != WM_GETICON &&
2800 message != WM_DEVICECHANGE)
2802 trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2804 switch (message)
2806 case WM_WINDOWPOSCHANGING:
2807 case WM_WINDOWPOSCHANGED:
2809 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2811 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2812 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2813 winpos->hwnd, winpos->hwndInsertAfter,
2814 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2815 dump_winpos_flags(winpos->flags);
2817 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2818 * in the high word for internal purposes
2820 wParam = winpos->flags & 0xffff;
2821 /* We are not interested in the flags that don't match under XP and Win9x */
2822 wParam &= ~(SWP_NOZORDER);
2823 break;
2826 case WM_MDIACTIVATE:
2828 HWND active, client = GetParent(hwnd);
2830 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2832 if (hwnd == (HWND)lParam) /* if we are being activated */
2833 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2834 else
2835 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2836 break;
2840 msg.message = message;
2841 msg.flags = sent|wparam|lparam;
2842 if (defwndproc_counter) msg.flags |= defwinproc;
2843 msg.wParam = wParam;
2844 msg.lParam = lParam;
2845 add_message(&msg);
2848 defwndproc_counter++;
2849 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2850 defwndproc_counter--;
2852 return ret;
2855 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2857 static long defwndproc_counter = 0;
2858 LRESULT ret;
2859 struct message msg;
2861 /* do not log painting messages */
2862 if (message != WM_PAINT &&
2863 message != WM_NCPAINT &&
2864 message != WM_SYNCPAINT &&
2865 message != WM_ERASEBKGND &&
2866 message != WM_NCPAINT &&
2867 message != WM_NCHITTEST &&
2868 message != WM_GETTEXT &&
2869 message != WM_GETICON &&
2870 message != WM_DEVICECHANGE)
2872 trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2874 switch (message)
2876 case WM_WINDOWPOSCHANGING:
2877 case WM_WINDOWPOSCHANGED:
2879 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2881 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2882 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2883 winpos->hwnd, winpos->hwndInsertAfter,
2884 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2885 dump_winpos_flags(winpos->flags);
2887 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2888 * in the high word for internal purposes
2890 wParam = winpos->flags & 0xffff;
2891 /* We are not interested in the flags that don't match under XP and Win9x */
2892 wParam &= ~(SWP_NOZORDER);
2893 break;
2897 msg.message = message;
2898 msg.flags = sent|wparam|lparam;
2899 if (defwndproc_counter) msg.flags |= defwinproc;
2900 msg.wParam = wParam;
2901 msg.lParam = lParam;
2902 add_message(&msg);
2905 defwndproc_counter++;
2906 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2907 defwndproc_counter--;
2909 return ret;
2912 static BOOL mdi_RegisterWindowClasses(void)
2914 WNDCLASSA cls;
2916 cls.style = 0;
2917 cls.lpfnWndProc = mdi_frame_wnd_proc;
2918 cls.cbClsExtra = 0;
2919 cls.cbWndExtra = 0;
2920 cls.hInstance = GetModuleHandleA(0);
2921 cls.hIcon = 0;
2922 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2923 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2924 cls.lpszMenuName = NULL;
2925 cls.lpszClassName = "MDI_frame_class";
2926 if (!RegisterClassA(&cls)) return FALSE;
2928 cls.lpfnWndProc = mdi_child_wnd_proc;
2929 cls.lpszClassName = "MDI_child_class";
2930 if (!RegisterClassA(&cls)) return FALSE;
2932 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
2933 old_mdi_client_proc = cls.lpfnWndProc;
2934 cls.hInstance = GetModuleHandleA(0);
2935 cls.lpfnWndProc = mdi_client_hook_proc;
2936 cls.lpszClassName = "MDI_client_class";
2937 if (!RegisterClassA(&cls)) assert(0);
2939 return TRUE;
2942 static void test_mdi_messages(void)
2944 MDICREATESTRUCTA mdi_cs;
2945 CLIENTCREATESTRUCT client_cs;
2946 HWND mdi_frame, mdi_child, mdi_child2, active_child;
2947 BOOL zoomed;
2948 HMENU hMenu = CreateMenu();
2950 assert(mdi_RegisterWindowClasses());
2952 flush_sequence();
2954 trace("creating MDI frame window\n");
2955 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
2956 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2957 WS_MAXIMIZEBOX | WS_VISIBLE,
2958 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
2959 GetDesktopWindow(), hMenu,
2960 GetModuleHandleA(0), NULL);
2961 assert(mdi_frame);
2962 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
2964 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2965 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
2967 trace("creating MDI client window\n");
2968 client_cs.hWindowMenu = 0;
2969 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
2970 mdi_client = CreateWindowExA(0, "MDI_client_class",
2971 NULL,
2972 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
2973 0, 0, 0, 0,
2974 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
2975 assert(mdi_client);
2976 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
2978 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2979 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
2981 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2982 ok(!active_child, "wrong active MDI child %p\n", active_child);
2983 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2985 SetFocus(0);
2986 flush_sequence();
2988 trace("creating invisible MDI child window\n");
2989 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2990 WS_CHILD,
2991 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2992 mdi_client, 0, GetModuleHandleA(0), NULL);
2993 assert(mdi_child);
2995 flush_sequence();
2996 ShowWindow(mdi_child, SW_SHOWNORMAL);
2997 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
2999 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3000 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3002 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3003 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3005 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3006 ok(!active_child, "wrong active MDI child %p\n", active_child);
3007 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3009 ShowWindow(mdi_child, SW_HIDE);
3010 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3011 flush_sequence();
3013 ShowWindow(mdi_child, SW_SHOW);
3014 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3016 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3017 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3019 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3020 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3022 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3023 ok(!active_child, "wrong active MDI child %p\n", active_child);
3024 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3026 DestroyWindow(mdi_child);
3027 flush_sequence();
3029 trace("creating visible MDI child window\n");
3030 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3031 WS_CHILD | WS_VISIBLE,
3032 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3033 mdi_client, 0, GetModuleHandleA(0), NULL);
3034 assert(mdi_child);
3035 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3037 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3038 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3040 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3041 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3043 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3044 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3045 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3046 flush_sequence();
3048 DestroyWindow(mdi_child);
3049 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3051 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3052 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3054 /* Win2k: MDI client still returns a just destroyed child as active
3055 * Win9x: MDI client returns 0
3057 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3058 ok(active_child == mdi_child || /* win2k */
3059 !active_child, /* win9x */
3060 "wrong active MDI child %p\n", active_child);
3061 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3063 flush_sequence();
3065 trace("creating invisible MDI child window\n");
3066 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3067 WS_CHILD,
3068 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3069 mdi_client, 0, GetModuleHandleA(0), NULL);
3070 assert(mdi_child2);
3071 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3073 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3074 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3076 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3077 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3079 /* Win2k: MDI client still returns a just destroyed child as active
3080 * Win9x: MDI client returns mdi_child2
3082 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3083 ok(active_child == mdi_child || /* win2k */
3084 active_child == mdi_child2, /* win9x */
3085 "wrong active MDI child %p\n", active_child);
3086 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3087 flush_sequence();
3089 ShowWindow(mdi_child2, SW_MAXIMIZE);
3090 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3092 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3093 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3095 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3096 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3097 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3098 flush_sequence();
3100 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3101 ok(GetFocus() == mdi_child2 || /* win2k */
3102 GetFocus() == 0, /* win9x */
3103 "wrong focus window %p\n", GetFocus());
3105 SetFocus(0);
3106 flush_sequence();
3108 ShowWindow(mdi_child2, SW_HIDE);
3109 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3111 ShowWindow(mdi_child2, SW_RESTORE);
3112 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3113 flush_sequence();
3115 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3116 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3118 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3119 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3120 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3121 flush_sequence();
3123 SetFocus(0);
3124 flush_sequence();
3126 ShowWindow(mdi_child2, SW_HIDE);
3127 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3129 ShowWindow(mdi_child2, SW_SHOW);
3130 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3132 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3133 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3135 ShowWindow(mdi_child2, SW_MAXIMIZE);
3136 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3138 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3139 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3141 ShowWindow(mdi_child2, SW_RESTORE);
3142 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3144 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3145 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3147 ShowWindow(mdi_child2, SW_MINIMIZE);
3148 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3150 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3151 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3153 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3154 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3155 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3156 flush_sequence();
3158 ShowWindow(mdi_child2, SW_RESTORE);
3159 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3161 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3162 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3164 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3165 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3166 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3167 flush_sequence();
3169 SetFocus(0);
3170 flush_sequence();
3172 ShowWindow(mdi_child2, SW_HIDE);
3173 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3175 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3176 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3178 DestroyWindow(mdi_child2);
3179 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3181 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3182 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3184 /* test for maximized MDI children */
3185 trace("creating maximized visible MDI child window 1\n");
3186 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3187 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3188 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3189 mdi_client, 0, GetModuleHandleA(0), NULL);
3190 assert(mdi_child);
3191 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3192 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3194 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3195 ok(GetFocus() == mdi_child || /* win2k */
3196 GetFocus() == 0, /* win9x */
3197 "wrong focus window %p\n", GetFocus());
3199 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3200 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3201 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3202 flush_sequence();
3204 trace("creating maximized visible MDI child window 2\n");
3205 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3206 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3207 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3208 mdi_client, 0, GetModuleHandleA(0), NULL);
3209 assert(mdi_child2);
3210 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3211 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3212 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3214 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3215 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3217 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3218 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3219 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3220 flush_sequence();
3222 trace("destroying maximized visible MDI child window 2\n");
3223 DestroyWindow(mdi_child2);
3224 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3226 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3228 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3229 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3231 /* Win2k: MDI client still returns a just destroyed child as active
3232 * Win9x: MDI client returns 0
3234 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3235 ok(active_child == mdi_child2 || /* win2k */
3236 !active_child, /* win9x */
3237 "wrong active MDI child %p\n", active_child);
3238 flush_sequence();
3240 ShowWindow(mdi_child, SW_MAXIMIZE);
3241 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3242 flush_sequence();
3244 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3245 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3247 trace("re-creating maximized visible MDI child window 2\n");
3248 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3249 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3250 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3251 mdi_client, 0, GetModuleHandleA(0), NULL);
3252 assert(mdi_child2);
3253 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3254 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3255 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3257 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3258 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3260 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3261 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3262 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3263 flush_sequence();
3265 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3266 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3267 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3269 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3270 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3271 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3273 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3274 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3275 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3276 flush_sequence();
3278 DestroyWindow(mdi_child);
3279 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3281 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3282 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3284 /* Win2k: MDI client still returns a just destroyed child as active
3285 * Win9x: MDI client returns 0
3287 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3288 ok(active_child == mdi_child || /* win2k */
3289 !active_child, /* win9x */
3290 "wrong active MDI child %p\n", active_child);
3291 flush_sequence();
3293 trace("creating maximized invisible MDI child window\n");
3294 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3295 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3296 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3297 mdi_client, 0, GetModuleHandleA(0), NULL);
3298 assert(mdi_child2);
3299 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE);
3300 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3301 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3302 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3304 /* Win2k: MDI client still returns a just destroyed child as active
3305 * Win9x: MDI client returns 0
3307 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3308 ok(active_child == mdi_child || /* win2k */
3309 !active_child, /* win9x */
3310 "wrong active MDI child %p\n", active_child);
3311 flush_sequence();
3313 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3314 ShowWindow(mdi_child2, SW_MAXIMIZE);
3315 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3316 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3317 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3318 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3320 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3321 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3322 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3323 flush_sequence();
3325 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3326 flush_sequence();
3328 /* end of test for maximized MDI children */
3329 SetFocus(0);
3330 flush_sequence();
3331 trace("creating maximized visible MDI child window 1(Switch test)\n");
3332 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3333 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3334 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3335 mdi_client, 0, GetModuleHandleA(0), NULL);
3336 assert(mdi_child);
3337 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3338 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3340 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3341 ok(GetFocus() == mdi_child || /* win2k */
3342 GetFocus() == 0, /* win9x */
3343 "wrong focus window %p(Switch test)\n", GetFocus());
3345 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3346 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3347 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3348 flush_sequence();
3350 trace("creating maximized visible MDI child window 2(Switch test)\n");
3351 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3352 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3353 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3354 mdi_client, 0, GetModuleHandleA(0), NULL);
3355 assert(mdi_child2);
3356 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3358 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3359 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3361 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3362 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3364 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3365 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3366 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3367 flush_sequence();
3369 trace("Switch child window.\n");
3370 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3371 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3372 trace("end of test for switch maximized MDI children\n");
3374 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3375 flush_sequence();
3377 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3378 flush_sequence();
3380 SetFocus(0);
3381 flush_sequence();
3382 /* end of test for switch maximized MDI children */
3384 mdi_cs.szClass = "MDI_child_Class";
3385 mdi_cs.szTitle = "MDI child";
3386 mdi_cs.hOwner = GetModuleHandleA(0);
3387 mdi_cs.x = 0;
3388 mdi_cs.y = 0;
3389 mdi_cs.cx = CW_USEDEFAULT;
3390 mdi_cs.cy = CW_USEDEFAULT;
3391 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3392 mdi_cs.lParam = 0;
3393 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3394 ok(mdi_child != 0, "MDI child creation failed\n");
3395 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3397 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3399 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3400 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3402 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3403 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3404 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3406 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3407 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3408 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3409 flush_sequence();
3411 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3412 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3414 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3415 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3416 ok(!active_child, "wrong active MDI child %p\n", active_child);
3418 SetFocus(0);
3419 flush_sequence();
3421 DestroyWindow(mdi_client);
3422 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3424 /* test maximization of MDI child with invisible parent */
3425 client_cs.hWindowMenu = 0;
3426 mdi_client = CreateWindow("MDI_client_class",
3427 NULL,
3428 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3429 0, 0, 660, 430,
3430 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3431 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3433 ShowWindow(mdi_client, SW_HIDE);
3434 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3436 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3437 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3438 0, 0, 650, 440,
3439 mdi_client, 0, GetModuleHandleA(0), NULL);
3440 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3442 SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3443 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3444 zoomed = IsZoomed(mdi_child);
3445 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3447 ShowWindow(mdi_client, SW_SHOW);
3448 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3450 DestroyWindow(mdi_child);
3451 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3453 /* end of test for maximization of MDI child with invisible parent */
3455 DestroyWindow(mdi_client);
3456 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3458 DestroyWindow(mdi_frame);
3459 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3461 /************************* End of MDI test **********************************/
3463 static void test_WM_SETREDRAW(HWND hwnd)
3465 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3467 flush_sequence();
3469 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3470 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3472 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3473 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3475 flush_sequence();
3476 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3477 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3479 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3480 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3482 /* restore original WS_VISIBLE state */
3483 SetWindowLongA(hwnd, GWL_STYLE, style);
3485 flush_sequence();
3488 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3490 struct message msg;
3492 trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3494 /* explicitly ignore WM_GETICON message */
3495 if (message == WM_GETICON) return 0;
3497 switch (message)
3499 /* ignore */
3500 case WM_MOUSEMOVE:
3501 case WM_SETCURSOR:
3502 case WM_DEVICECHANGE:
3503 return 0;
3504 case WM_NCHITTEST:
3505 return HTCLIENT;
3507 case WM_WINDOWPOSCHANGING:
3508 case WM_WINDOWPOSCHANGED:
3510 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3512 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3513 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3514 winpos->hwnd, winpos->hwndInsertAfter,
3515 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3516 dump_winpos_flags(winpos->flags);
3518 /* Log only documented flags, win2k uses 0x1000 and 0x2000
3519 * in the high word for internal purposes
3521 wParam = winpos->flags & 0xffff;
3522 /* We are not interested in the flags that don't match under XP and Win9x */
3523 wParam &= ~(SWP_NOZORDER);
3524 break;
3528 msg.message = message;
3529 msg.flags = sent|wparam|lparam;
3530 msg.wParam = wParam;
3531 msg.lParam = lParam;
3532 add_message(&msg);
3534 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3535 if (message == WM_TIMER) EndDialog( hwnd, 0 );
3536 return 0;
3539 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3541 DWORD style, exstyle;
3542 INT xmin, xmax;
3543 BOOL ret;
3545 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3546 style = GetWindowLongA(hwnd, GWL_STYLE);
3547 /* do not be confused by WS_DLGFRAME set */
3548 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3550 if (clear) ok(style & clear, "style %08x should be set\n", clear);
3551 if (set) ok(!(style & set), "style %08x should not be set\n", set);
3553 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3554 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3555 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3556 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3557 else
3558 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3560 style = GetWindowLongA(hwnd, GWL_STYLE);
3561 if (set) ok(style & set, "style %08x should be set\n", set);
3562 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3564 /* a subsequent call should do nothing */
3565 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3566 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3567 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3569 xmin = 0xdeadbeef;
3570 xmax = 0xdeadbeef;
3571 trace("Ignore GetScrollRange error below if you are on Win9x\n");
3572 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3573 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3574 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3575 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3576 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3579 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3581 DWORD style, exstyle;
3582 SCROLLINFO si;
3583 BOOL ret;
3585 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3586 style = GetWindowLongA(hwnd, GWL_STYLE);
3587 /* do not be confused by WS_DLGFRAME set */
3588 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3590 if (clear) ok(style & clear, "style %08x should be set\n", clear);
3591 if (set) ok(!(style & set), "style %08x should not be set\n", set);
3593 si.cbSize = sizeof(si);
3594 si.fMask = SIF_RANGE;
3595 si.nMin = min;
3596 si.nMax = max;
3597 SetScrollInfo(hwnd, ctl, &si, TRUE);
3598 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3599 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3600 else
3601 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3603 style = GetWindowLongA(hwnd, GWL_STYLE);
3604 if (set) ok(style & set, "style %08x should be set\n", set);
3605 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3607 /* a subsequent call should do nothing */
3608 SetScrollInfo(hwnd, ctl, &si, TRUE);
3609 if (style & WS_HSCROLL)
3610 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3611 else if (style & WS_VSCROLL)
3612 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3613 else
3614 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3616 si.fMask = SIF_PAGE;
3617 si.nPage = 5;
3618 SetScrollInfo(hwnd, ctl, &si, FALSE);
3619 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3621 si.fMask = SIF_POS;
3622 si.nPos = max - 1;
3623 SetScrollInfo(hwnd, ctl, &si, FALSE);
3624 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3626 si.fMask = SIF_RANGE;
3627 si.nMin = 0xdeadbeef;
3628 si.nMax = 0xdeadbeef;
3629 ret = GetScrollInfo(hwnd, ctl, &si);
3630 ok( ret, "GetScrollInfo error %d\n", GetLastError());
3631 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3632 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3633 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3636 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3637 static void test_scroll_messages(HWND hwnd)
3639 SCROLLINFO si;
3640 INT min, max;
3641 BOOL ret;
3643 min = 0xdeadbeef;
3644 max = 0xdeadbeef;
3645 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3646 ok( ret, "GetScrollRange error %d\n", GetLastError());
3647 if (sequence->message != WmGetScrollRangeSeq[0].message)
3648 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3649 /* values of min and max are undefined */
3650 flush_sequence();
3652 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3653 ok( ret, "SetScrollRange error %d\n", GetLastError());
3654 if (sequence->message != WmSetScrollRangeSeq[0].message)
3655 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3656 flush_sequence();
3658 min = 0xdeadbeef;
3659 max = 0xdeadbeef;
3660 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3661 ok( ret, "GetScrollRange error %d\n", GetLastError());
3662 if (sequence->message != WmGetScrollRangeSeq[0].message)
3663 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3664 /* values of min and max are undefined */
3665 flush_sequence();
3667 si.cbSize = sizeof(si);
3668 si.fMask = SIF_RANGE;
3669 si.nMin = 20;
3670 si.nMax = 160;
3671 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3672 if (sequence->message != WmSetScrollRangeSeq[0].message)
3673 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3674 flush_sequence();
3676 si.fMask = SIF_PAGE;
3677 si.nPage = 10;
3678 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3679 if (sequence->message != WmSetScrollRangeSeq[0].message)
3680 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3681 flush_sequence();
3683 si.fMask = SIF_POS;
3684 si.nPos = 20;
3685 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3686 if (sequence->message != WmSetScrollRangeSeq[0].message)
3687 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3688 flush_sequence();
3690 si.fMask = SIF_RANGE;
3691 si.nMin = 0xdeadbeef;
3692 si.nMax = 0xdeadbeef;
3693 ret = GetScrollInfo(hwnd, SB_CTL, &si);
3694 ok( ret, "GetScrollInfo error %d\n", GetLastError());
3695 if (sequence->message != WmGetScrollInfoSeq[0].message)
3696 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3697 /* values of min and max are undefined */
3698 flush_sequence();
3700 /* set WS_HSCROLL */
3701 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3702 /* clear WS_HSCROLL */
3703 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3705 /* set WS_HSCROLL */
3706 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3707 /* clear WS_HSCROLL */
3708 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3710 /* set WS_VSCROLL */
3711 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3712 /* clear WS_VSCROLL */
3713 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3715 /* set WS_VSCROLL */
3716 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3717 /* clear WS_VSCROLL */
3718 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3721 static void test_showwindow(void)
3723 HWND hwnd, hchild;
3724 RECT rc;
3726 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3727 100, 100, 200, 200, 0, 0, 0, NULL);
3728 ok (hwnd != 0, "Failed to create overlapped window\n");
3729 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3730 0, 0, 10, 10, hwnd, 0, 0, NULL);
3731 ok (hchild != 0, "Failed to create child\n");
3732 flush_sequence();
3734 /* ShowWindow( SW_SHOWNA) for invisible top level window */
3735 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3736 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3737 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3738 trace("done\n");
3740 /* ShowWindow( SW_SHOWNA) for now visible top level window */
3741 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3742 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3743 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3744 trace("done\n");
3745 /* back to invisible */
3746 ShowWindow(hchild, SW_HIDE);
3747 ShowWindow(hwnd, SW_HIDE);
3748 flush_sequence();
3749 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
3750 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3751 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3752 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3753 trace("done\n");
3754 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
3755 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3756 flush_sequence();
3757 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3758 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3759 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3760 trace("done\n");
3761 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3762 ShowWindow( hwnd, SW_SHOW);
3763 flush_sequence();
3764 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3765 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3766 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3767 trace("done\n");
3769 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3770 ShowWindow( hchild, SW_HIDE);
3771 flush_sequence();
3772 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3773 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3774 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3775 trace("done\n");
3777 SetCapture(hchild);
3778 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3779 DestroyWindow(hchild);
3780 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3782 DestroyWindow(hwnd);
3783 flush_sequence();
3785 /* Popup windows */
3786 /* Test 1:
3787 * 1. Create invisible maximized popup window.
3788 * 2. Move and resize it.
3789 * 3. Show it maximized.
3791 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3792 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3793 100, 100, 200, 200, 0, 0, 0, NULL);
3794 ok (hwnd != 0, "Failed to create popup window\n");
3795 ok(IsZoomed(hwnd), "window should be maximized\n");
3796 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3797 trace("done\n");
3799 GetWindowRect(hwnd, &rc);
3800 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3801 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3802 "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3803 rc.left, rc.top, rc.right, rc.bottom);
3804 /* Reset window's size & position */
3805 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3806 ok(IsZoomed(hwnd), "window should be maximized\n");
3807 flush_sequence();
3809 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3810 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3811 ok(IsZoomed(hwnd), "window should be maximized\n");
3812 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3813 trace("done\n");
3815 GetWindowRect(hwnd, &rc);
3816 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3817 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3818 "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3819 rc.left, rc.top, rc.right, rc.bottom);
3820 DestroyWindow(hwnd);
3821 flush_sequence();
3823 /* Test 2:
3824 * 1. Create invisible maximized popup window.
3825 * 2. Show it maximized.
3827 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3828 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3829 100, 100, 200, 200, 0, 0, 0, NULL);
3830 ok (hwnd != 0, "Failed to create popup window\n");
3831 ok(IsZoomed(hwnd), "window should be maximized\n");
3832 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3833 trace("done\n");
3835 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3836 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3837 ok(IsZoomed(hwnd), "window should be maximized\n");
3838 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
3839 trace("done\n");
3840 DestroyWindow(hwnd);
3841 flush_sequence();
3843 /* Test 3:
3844 * 1. Create visible maximized popup window.
3846 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
3847 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3848 100, 100, 200, 200, 0, 0, 0, NULL);
3849 ok (hwnd != 0, "Failed to create popup window\n");
3850 ok(IsZoomed(hwnd), "window should be maximized\n");
3851 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3852 trace("done\n");
3853 DestroyWindow(hwnd);
3854 flush_sequence();
3856 /* Test 4:
3857 * 1. Create visible popup window.
3858 * 2. Maximize it.
3860 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
3861 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
3862 100, 100, 200, 200, 0, 0, 0, NULL);
3863 ok (hwnd != 0, "Failed to create popup window\n");
3864 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
3865 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
3866 trace("done\n");
3868 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
3869 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3870 ok(IsZoomed(hwnd), "window should be maximized\n");
3871 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3872 trace("done\n");
3873 DestroyWindow(hwnd);
3874 flush_sequence();
3877 static void test_sys_menu(void)
3879 HWND hwnd;
3880 HMENU hmenu;
3881 UINT state;
3883 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3884 100, 100, 200, 200, 0, 0, 0, NULL);
3885 ok (hwnd != 0, "Failed to create overlapped window\n");
3887 flush_sequence();
3889 /* test existing window without CS_NOCLOSE style */
3890 hmenu = GetSystemMenu(hwnd, FALSE);
3891 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3893 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3894 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3895 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3897 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
3898 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3900 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3901 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3902 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
3904 EnableMenuItem(hmenu, SC_CLOSE, 0);
3905 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3907 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3908 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3909 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3911 /* test whether removing WS_SYSMENU destroys a system menu */
3912 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
3913 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3914 flush_sequence();
3915 hmenu = GetSystemMenu(hwnd, FALSE);
3916 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3918 DestroyWindow(hwnd);
3920 /* test new window with CS_NOCLOSE style */
3921 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3922 100, 100, 200, 200, 0, 0, 0, NULL);
3923 ok (hwnd != 0, "Failed to create overlapped window\n");
3925 hmenu = GetSystemMenu(hwnd, FALSE);
3926 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3928 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3929 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3931 DestroyWindow(hwnd);
3933 /* test new window without WS_SYSMENU style */
3934 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
3935 100, 100, 200, 200, 0, 0, 0, NULL);
3936 ok(hwnd != 0, "Failed to create overlapped window\n");
3938 hmenu = GetSystemMenu(hwnd, FALSE);
3939 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
3941 DestroyWindow(hwnd);
3944 /* For shown WS_OVERLAPPEDWINDOW */
3945 static const struct message WmSetIcon_1[] = {
3946 { WM_SETICON, sent },
3947 { 0x00AE, sent|defwinproc|optional }, /* XP */
3948 { WM_GETTEXT, sent|defwinproc|optional },
3949 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
3950 { 0 }
3953 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
3954 static const struct message WmSetIcon_2[] = {
3955 { WM_SETICON, sent },
3956 { 0 }
3959 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
3960 static const struct message WmInitEndSession[] = {
3961 { 0x003B, sent },
3962 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
3963 { 0 }
3966 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
3967 static const struct message WmInitEndSession_2[] = {
3968 { 0x003B, sent },
3969 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
3970 { 0 }
3973 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
3974 static const struct message WmInitEndSession_3[] = {
3975 { 0x003B, sent },
3976 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
3977 { 0 }
3980 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
3981 static const struct message WmInitEndSession_4[] = {
3982 { 0x003B, sent },
3983 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
3984 { 0 }
3987 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
3988 static const struct message WmInitEndSession_5[] = {
3989 { 0x003B, sent },
3990 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 1, ENDSESSION_LOGOFF },
3991 { 0 }
3994 static void test_MsgWaitForMultipleObjects(HWND hwnd)
3996 DWORD ret;
3997 MSG msg;
3999 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4000 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4002 PostMessageA(hwnd, WM_USER, 0, 0);
4004 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4005 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4007 ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4008 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4010 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4011 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4013 PostMessageA(hwnd, WM_USER, 0, 0);
4015 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4016 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4018 ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4019 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4021 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4022 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4023 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4025 PostMessageA(hwnd, WM_USER, 0, 0);
4027 /* new incoming message causes it to become signaled again */
4028 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4029 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4031 ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4032 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4033 ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4034 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4037 /* test if we receive the right sequence of messages */
4038 static void test_messages(void)
4040 HWND hwnd, hparent, hchild;
4041 HWND hchild2, hbutton;
4042 HMENU hmenu;
4043 MSG msg;
4044 LRESULT res;
4046 flush_sequence();
4048 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4049 100, 100, 200, 200, 0, 0, 0, NULL);
4050 ok (hwnd != 0, "Failed to create overlapped window\n");
4051 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4053 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4054 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4055 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4057 /* test WM_SETREDRAW on a not visible top level window */
4058 test_WM_SETREDRAW(hwnd);
4060 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4061 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4062 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4064 ok(GetActiveWindow() == hwnd, "window should be active\n");
4065 ok(GetFocus() == hwnd, "window should have input focus\n");
4066 ShowWindow(hwnd, SW_HIDE);
4067 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
4069 ShowWindow(hwnd, SW_SHOW);
4070 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4072 ShowWindow(hwnd, SW_HIDE);
4073 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4075 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4076 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4078 ShowWindow(hwnd, SW_RESTORE);
4079 /* FIXME: add ok_sequence() here */
4080 flush_sequence();
4082 ShowWindow(hwnd, SW_MINIMIZE);
4083 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4084 flush_sequence();
4086 ShowWindow(hwnd, SW_RESTORE);
4087 /* FIXME: add ok_sequence() here */
4088 flush_sequence();
4090 ShowWindow(hwnd, SW_SHOW);
4091 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4093 ok(GetActiveWindow() == hwnd, "window should be active\n");
4094 ok(GetFocus() == hwnd, "window should have input focus\n");
4095 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4096 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4097 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4098 ok(GetActiveWindow() == hwnd, "window should still be active\n");
4100 /* test WM_SETREDRAW on a visible top level window */
4101 ShowWindow(hwnd, SW_SHOW);
4102 test_WM_SETREDRAW(hwnd);
4104 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4105 test_scroll_messages(hwnd);
4107 /* test resizing and moving */
4108 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4109 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4110 flush_events();
4111 flush_sequence();
4112 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4113 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4114 flush_events();
4115 flush_sequence();
4116 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER );
4117 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4118 flush_events();
4119 flush_sequence();
4121 /* popups don't get WM_GETMINMAXINFO */
4122 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4123 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4124 flush_sequence();
4125 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4126 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4128 DestroyWindow(hwnd);
4129 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4131 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4132 100, 100, 200, 200, 0, 0, 0, NULL);
4133 ok (hparent != 0, "Failed to create parent window\n");
4134 flush_sequence();
4136 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4137 0, 0, 10, 10, hparent, 0, 0, NULL);
4138 ok (hchild != 0, "Failed to create child window\n");
4139 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4140 DestroyWindow(hchild);
4141 flush_sequence();
4143 /* visible child window with a caption */
4144 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4145 WS_CHILD | WS_VISIBLE | WS_CAPTION,
4146 0, 0, 10, 10, hparent, 0, 0, NULL);
4147 ok (hchild != 0, "Failed to create child window\n");
4148 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4150 trace("testing scroll APIs on a visible child window %p\n", hchild);
4151 test_scroll_messages(hchild);
4153 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4154 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4156 DestroyWindow(hchild);
4157 flush_sequence();
4159 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4160 0, 0, 10, 10, hparent, 0, 0, NULL);
4161 ok (hchild != 0, "Failed to create child window\n");
4162 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4164 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4165 100, 100, 50, 50, hparent, 0, 0, NULL);
4166 ok (hchild2 != 0, "Failed to create child2 window\n");
4167 flush_sequence();
4169 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4170 0, 100, 50, 50, hchild, 0, 0, NULL);
4171 ok (hbutton != 0, "Failed to create button window\n");
4173 /* test WM_SETREDRAW on a not visible child window */
4174 test_WM_SETREDRAW(hchild);
4176 ShowWindow(hchild, SW_SHOW);
4177 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4179 /* check parent messages too */
4180 log_all_parent_messages++;
4181 ShowWindow(hchild, SW_HIDE);
4182 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4183 log_all_parent_messages--;
4185 ShowWindow(hchild, SW_SHOW);
4186 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4188 ShowWindow(hchild, SW_HIDE);
4189 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4191 ShowWindow(hchild, SW_SHOW);
4192 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4194 /* test WM_SETREDRAW on a visible child window */
4195 test_WM_SETREDRAW(hchild);
4197 log_all_parent_messages++;
4198 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4199 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4200 log_all_parent_messages--;
4202 ShowWindow(hchild, SW_HIDE);
4203 flush_sequence();
4204 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4205 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4207 ShowWindow(hchild, SW_HIDE);
4208 flush_sequence();
4209 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4210 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4212 /* DestroyWindow sequence below expects that a child has focus */
4213 SetFocus(hchild);
4214 flush_sequence();
4216 DestroyWindow(hchild);
4217 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4218 DestroyWindow(hchild2);
4219 DestroyWindow(hbutton);
4221 flush_sequence();
4222 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4223 0, 0, 100, 100, hparent, 0, 0, NULL);
4224 ok (hchild != 0, "Failed to create child popup window\n");
4225 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4226 DestroyWindow(hchild);
4228 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4229 flush_sequence();
4230 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4231 0, 0, 100, 100, hparent, 0, 0, NULL);
4232 ok (hchild != 0, "Failed to create popup window\n");
4233 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4234 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4235 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4236 flush_sequence();
4237 ShowWindow(hchild, SW_SHOW);
4238 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4239 flush_sequence();
4240 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4241 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4242 flush_sequence();
4243 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4244 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", TRUE);
4245 DestroyWindow(hchild);
4247 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4248 * changes nothing in message sequences.
4250 flush_sequence();
4251 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4252 0, 0, 100, 100, hparent, 0, 0, NULL);
4253 ok (hchild != 0, "Failed to create popup window\n");
4254 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4255 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4256 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4257 flush_sequence();
4258 ShowWindow(hchild, SW_SHOW);
4259 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4260 flush_sequence();
4261 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4262 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4263 DestroyWindow(hchild);
4265 flush_sequence();
4266 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4267 0, 0, 100, 100, hparent, 0, 0, NULL);
4268 ok(hwnd != 0, "Failed to create custom dialog window\n");
4269 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4272 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4273 test_scroll_messages(hwnd);
4276 flush_sequence();
4278 test_def_id = 1;
4279 SendMessage(hwnd, WM_NULL, 0, 0);
4281 flush_sequence();
4282 after_end_dialog = 1;
4283 EndDialog( hwnd, 0 );
4284 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4286 DestroyWindow(hwnd);
4287 after_end_dialog = 0;
4288 test_def_id = 0;
4290 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4291 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4292 ok(hwnd != 0, "Failed to create custom dialog window\n");
4293 flush_sequence();
4294 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4295 ShowWindow(hwnd, SW_SHOW);
4296 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4297 DestroyWindow(hwnd);
4299 flush_sequence();
4300 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4301 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4303 DestroyWindow(hparent);
4304 flush_sequence();
4306 /* Message sequence for SetMenu */
4307 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4308 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4310 hmenu = CreateMenu();
4311 ok (hmenu != 0, "Failed to create menu\n");
4312 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4313 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4314 100, 100, 200, 200, 0, hmenu, 0, NULL);
4315 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4316 ok (SetMenu(hwnd, 0), "SetMenu\n");
4317 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4318 ok (SetMenu(hwnd, 0), "SetMenu\n");
4319 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4320 ShowWindow(hwnd, SW_SHOW);
4321 UpdateWindow( hwnd );
4322 flush_events();
4323 flush_sequence();
4324 ok (SetMenu(hwnd, 0), "SetMenu\n");
4325 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4326 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4327 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4329 UpdateWindow( hwnd );
4330 flush_events();
4331 flush_sequence();
4332 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4333 flush_events();
4334 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4336 DestroyWindow(hwnd);
4337 flush_sequence();
4339 /* Message sequence for EnableWindow */
4340 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4341 100, 100, 200, 200, 0, 0, 0, NULL);
4342 ok (hparent != 0, "Failed to create parent window\n");
4343 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4344 0, 0, 10, 10, hparent, 0, 0, NULL);
4345 ok (hchild != 0, "Failed to create child window\n");
4347 SetFocus(hchild);
4348 flush_events();
4349 flush_sequence();
4351 EnableWindow(hparent, FALSE);
4352 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4354 EnableWindow(hparent, TRUE);
4355 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4357 flush_events();
4358 flush_sequence();
4360 test_MsgWaitForMultipleObjects(hparent);
4362 /* the following test causes an exception in user.exe under win9x */
4363 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4365 DestroyWindow(hparent);
4366 flush_sequence();
4367 return;
4369 PostMessageW( hparent, WM_USER+1, 0, 0 );
4370 /* PeekMessage(NULL) fails, but still removes the message */
4371 SetLastError(0xdeadbeef);
4372 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4373 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4374 GetLastError() == 0xdeadbeef, /* NT4 */
4375 "last error is %d\n", GetLastError() );
4376 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4377 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4379 DestroyWindow(hchild);
4380 DestroyWindow(hparent);
4381 flush_sequence();
4383 /* Message sequences for WM_SETICON */
4384 trace("testing WM_SETICON\n");
4385 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4386 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4387 NULL, NULL, 0);
4388 ShowWindow(hwnd, SW_SHOW);
4389 UpdateWindow(hwnd);
4390 flush_events();
4391 flush_sequence();
4392 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4393 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4395 ShowWindow(hwnd, SW_HIDE);
4396 flush_events();
4397 flush_sequence();
4398 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4399 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4400 DestroyWindow(hwnd);
4401 flush_sequence();
4403 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4404 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4405 NULL, NULL, 0);
4406 ShowWindow(hwnd, SW_SHOW);
4407 UpdateWindow(hwnd);
4408 flush_events();
4409 flush_sequence();
4410 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4411 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4413 ShowWindow(hwnd, SW_HIDE);
4414 flush_events();
4415 flush_sequence();
4416 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4417 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4419 flush_sequence();
4420 res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4421 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4422 todo_wine
4423 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4424 res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4425 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4426 todo_wine
4427 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4428 res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4429 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4430 todo_wine
4431 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4433 flush_sequence();
4434 res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4435 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4436 todo_wine
4437 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4438 res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4439 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4440 todo_wine
4441 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4443 res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4444 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4445 todo_wine
4446 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4448 res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4449 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4450 todo_wine
4451 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4453 DestroyWindow(hwnd);
4454 flush_sequence();
4457 static void invisible_parent_tests(void)
4459 HWND hparent, hchild;
4461 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4462 100, 100, 200, 200, 0, 0, 0, NULL);
4463 ok (hparent != 0, "Failed to create parent window\n");
4464 flush_sequence();
4466 /* test showing child with hidden parent */
4468 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4469 0, 0, 10, 10, hparent, 0, 0, NULL);
4470 ok (hchild != 0, "Failed to create child window\n");
4471 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4473 ShowWindow( hchild, SW_MINIMIZE );
4474 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4475 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4476 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4478 /* repeat */
4479 flush_events();
4480 flush_sequence();
4481 ShowWindow( hchild, SW_MINIMIZE );
4482 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4484 DestroyWindow(hchild);
4485 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4486 0, 0, 10, 10, hparent, 0, 0, NULL);
4487 flush_sequence();
4489 ShowWindow( hchild, SW_MAXIMIZE );
4490 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4491 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4492 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4494 /* repeat */
4495 flush_events();
4496 flush_sequence();
4497 ShowWindow( hchild, SW_MAXIMIZE );
4498 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4500 DestroyWindow(hchild);
4501 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4502 0, 0, 10, 10, hparent, 0, 0, NULL);
4503 flush_sequence();
4505 ShowWindow( hchild, SW_RESTORE );
4506 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4507 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4508 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4510 DestroyWindow(hchild);
4511 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4512 0, 0, 10, 10, hparent, 0, 0, NULL);
4513 flush_sequence();
4515 ShowWindow( hchild, SW_SHOWMINIMIZED );
4516 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4517 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4518 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4520 /* repeat */
4521 flush_events();
4522 flush_sequence();
4523 ShowWindow( hchild, SW_SHOWMINIMIZED );
4524 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4526 DestroyWindow(hchild);
4527 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4528 0, 0, 10, 10, hparent, 0, 0, NULL);
4529 flush_sequence();
4531 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4532 ShowWindow( hchild, SW_SHOWMAXIMIZED );
4533 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4534 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4535 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4537 DestroyWindow(hchild);
4538 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4539 0, 0, 10, 10, hparent, 0, 0, NULL);
4540 flush_sequence();
4542 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4543 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4544 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4545 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4547 /* repeat */
4548 flush_events();
4549 flush_sequence();
4550 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4551 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4553 DestroyWindow(hchild);
4554 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4555 0, 0, 10, 10, hparent, 0, 0, NULL);
4556 flush_sequence();
4558 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4559 ShowWindow( hchild, SW_FORCEMINIMIZE );
4560 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4561 todo_wine {
4562 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4564 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4566 DestroyWindow(hchild);
4567 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4568 0, 0, 10, 10, hparent, 0, 0, NULL);
4569 flush_sequence();
4571 ShowWindow( hchild, SW_SHOWNA );
4572 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4573 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4574 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4576 /* repeat */
4577 flush_events();
4578 flush_sequence();
4579 ShowWindow( hchild, SW_SHOWNA );
4580 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4582 DestroyWindow(hchild);
4583 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4584 0, 0, 10, 10, hparent, 0, 0, NULL);
4585 flush_sequence();
4587 ShowWindow( hchild, SW_SHOW );
4588 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4589 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4590 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4592 /* repeat */
4593 flush_events();
4594 flush_sequence();
4595 ShowWindow( hchild, SW_SHOW );
4596 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4598 ShowWindow( hchild, SW_HIDE );
4599 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4600 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4601 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4603 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4604 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4605 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4606 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4608 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4609 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4610 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4611 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4613 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4614 flush_sequence();
4615 DestroyWindow(hchild);
4616 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4618 DestroyWindow(hparent);
4619 flush_sequence();
4622 /****************** button message test *************************/
4623 static const struct message WmSetFocusButtonSeq[] =
4625 { HCBT_SETFOCUS, hook },
4626 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4627 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4628 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4629 { WM_SETFOCUS, sent|wparam, 0 },
4630 { WM_CTLCOLORBTN, sent|defwinproc },
4631 { 0 }
4633 static const struct message WmKillFocusButtonSeq[] =
4635 { HCBT_SETFOCUS, hook },
4636 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4637 { WM_KILLFOCUS, sent|wparam, 0 },
4638 { WM_CTLCOLORBTN, sent|defwinproc },
4639 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4640 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4641 { 0 }
4643 static const struct message WmSetFocusStaticSeq[] =
4645 { HCBT_SETFOCUS, hook },
4646 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4647 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4648 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4649 { WM_SETFOCUS, sent|wparam, 0 },
4650 { WM_CTLCOLORSTATIC, sent|defwinproc },
4651 { 0 }
4653 static const struct message WmKillFocusStaticSeq[] =
4655 { HCBT_SETFOCUS, hook },
4656 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4657 { WM_KILLFOCUS, sent|wparam, 0 },
4658 { WM_CTLCOLORSTATIC, sent|defwinproc },
4659 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4660 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4661 { 0 }
4663 static const struct message WmLButtonDownSeq[] =
4665 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4666 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4667 { HCBT_SETFOCUS, hook },
4668 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4669 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4670 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4671 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4672 { WM_CTLCOLORBTN, sent|defwinproc },
4673 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4674 { WM_CTLCOLORBTN, sent|defwinproc },
4675 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4676 { 0 }
4678 static const struct message WmLButtonUpSeq[] =
4680 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4681 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4682 { WM_CTLCOLORBTN, sent|defwinproc },
4683 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4684 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4685 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4686 { 0 }
4688 static const struct message WmSetFontButtonSeq[] =
4690 { WM_SETFONT, sent },
4691 { WM_PAINT, sent },
4692 { WM_ERASEBKGND, sent|defwinproc|optional },
4693 { WM_CTLCOLORBTN, sent|defwinproc },
4694 { 0 }
4697 static WNDPROC old_button_proc;
4699 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4701 static long defwndproc_counter = 0;
4702 LRESULT ret;
4703 struct message msg;
4705 trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4707 /* explicitly ignore WM_GETICON message */
4708 if (message == WM_GETICON) return 0;
4710 msg.message = message;
4711 msg.flags = sent|wparam|lparam;
4712 if (defwndproc_counter) msg.flags |= defwinproc;
4713 msg.wParam = wParam;
4714 msg.lParam = lParam;
4715 add_message(&msg);
4717 if (message == BM_SETSTATE)
4718 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4720 defwndproc_counter++;
4721 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4722 defwndproc_counter--;
4724 return ret;
4727 static void subclass_button(void)
4729 WNDCLASSA cls;
4731 if (!GetClassInfoA(0, "button", &cls)) assert(0);
4733 old_button_proc = cls.lpfnWndProc;
4735 cls.hInstance = GetModuleHandle(0);
4736 cls.lpfnWndProc = button_hook_proc;
4737 cls.lpszClassName = "my_button_class";
4738 UnregisterClass(cls.lpszClassName, cls.hInstance);
4739 if (!RegisterClassA(&cls)) assert(0);
4742 static void test_button_messages(void)
4744 static const struct
4746 DWORD style;
4747 DWORD dlg_code;
4748 const struct message *setfocus;
4749 const struct message *killfocus;
4750 } button[] = {
4751 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4752 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4753 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4754 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4755 { BS_CHECKBOX, DLGC_BUTTON,
4756 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4757 { BS_AUTOCHECKBOX, DLGC_BUTTON,
4758 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4759 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4760 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4761 { BS_3STATE, DLGC_BUTTON,
4762 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4763 { BS_AUTO3STATE, DLGC_BUTTON,
4764 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4765 { BS_GROUPBOX, DLGC_STATIC,
4766 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4767 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4768 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4769 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4770 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4771 { BS_OWNERDRAW, DLGC_BUTTON,
4772 WmSetFocusButtonSeq, WmKillFocusButtonSeq }
4774 unsigned int i;
4775 HWND hwnd;
4776 DWORD dlg_code;
4777 HFONT zfont;
4779 subclass_button();
4781 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
4783 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
4784 0, 0, 50, 14, 0, 0, 0, NULL);
4785 ok(hwnd != 0, "Failed to create button window\n");
4787 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4788 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4790 ShowWindow(hwnd, SW_SHOW);
4791 UpdateWindow(hwnd);
4792 SetFocus(0);
4793 flush_sequence();
4795 trace("button style %08x\n", button[i].style);
4796 SetFocus(hwnd);
4797 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
4799 SetFocus(0);
4800 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
4802 DestroyWindow(hwnd);
4805 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
4806 0, 0, 50, 14, 0, 0, 0, NULL);
4807 ok(hwnd != 0, "Failed to create button window\n");
4809 SetFocus(0);
4810 flush_events();
4811 flush_sequence();
4813 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
4814 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
4816 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
4817 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
4819 flush_sequence();
4820 zfont = (HFONT)GetStockObject(SYSTEM_FONT);
4821 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
4822 UpdateWindow(hwnd);
4823 ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
4825 DestroyWindow(hwnd);
4828 /****************** static message test *************************/
4829 static const struct message WmSetFontStaticSeq[] =
4831 { WM_SETFONT, sent },
4832 { WM_PAINT, sent|defwinproc },
4833 { WM_ERASEBKGND, sent|defwinproc|optional },
4834 { WM_CTLCOLORSTATIC, sent|defwinproc },
4835 { 0 }
4838 static WNDPROC old_static_proc;
4840 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4842 static long defwndproc_counter = 0;
4843 LRESULT ret;
4844 struct message msg;
4846 trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4848 /* explicitly ignore WM_GETICON message */
4849 if (message == WM_GETICON) return 0;
4851 msg.message = message;
4852 msg.flags = sent|wparam|lparam;
4853 if (defwndproc_counter) msg.flags |= defwinproc;
4854 msg.wParam = wParam;
4855 msg.lParam = lParam;
4856 add_message(&msg);
4859 defwndproc_counter++;
4860 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
4861 defwndproc_counter--;
4863 return ret;
4866 static void subclass_static(void)
4868 WNDCLASSA cls;
4870 if (!GetClassInfoA(0, "static", &cls)) assert(0);
4872 old_static_proc = cls.lpfnWndProc;
4874 cls.hInstance = GetModuleHandle(0);
4875 cls.lpfnWndProc = static_hook_proc;
4876 cls.lpszClassName = "my_static_class";
4877 UnregisterClass(cls.lpszClassName, cls.hInstance);
4878 if (!RegisterClassA(&cls)) assert(0);
4881 static void test_static_messages(void)
4883 /* FIXME: make as comprehensive as the button message test */
4884 static const struct
4886 DWORD style;
4887 DWORD dlg_code;
4888 const struct message *setfont;
4889 } static_ctrl[] = {
4890 { SS_LEFT, DLGC_STATIC,
4891 WmSetFontStaticSeq }
4893 unsigned int i;
4894 HWND hwnd;
4895 DWORD dlg_code;
4897 subclass_static();
4899 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
4901 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
4902 0, 0, 50, 14, 0, 0, 0, NULL);
4903 ok(hwnd != 0, "Failed to create static window\n");
4905 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4906 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4908 ShowWindow(hwnd, SW_SHOW);
4909 UpdateWindow(hwnd);
4910 SetFocus(0);
4911 flush_sequence();
4913 trace("static style %08x\n", static_ctrl[i].style);
4914 SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
4915 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
4917 DestroyWindow(hwnd);
4921 /************* painting message test ********************/
4923 void dump_region(HRGN hrgn)
4925 DWORD i, size;
4926 RGNDATA *data = NULL;
4927 RECT *rect;
4929 if (!hrgn)
4931 printf( "null region\n" );
4932 return;
4934 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
4935 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
4936 GetRegionData( hrgn, size, data );
4937 printf("%d rects:", data->rdh.nCount );
4938 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
4939 printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
4940 printf("\n");
4941 HeapFree( GetProcessHeap(), 0, data );
4944 static void check_update_rgn( HWND hwnd, HRGN hrgn )
4946 INT ret;
4947 RECT r1, r2;
4948 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
4949 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
4951 ret = GetUpdateRgn( hwnd, update, FALSE );
4952 ok( ret != ERROR, "GetUpdateRgn failed\n" );
4953 if (ret == NULLREGION)
4955 ok( !hrgn, "Update region shouldn't be empty\n" );
4957 else
4959 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
4961 ok( 0, "Regions are different\n" );
4962 if (winetest_debug > 0)
4964 printf( "Update region: " );
4965 dump_region( update );
4966 printf( "Wanted region: " );
4967 dump_region( hrgn );
4971 GetRgnBox( update, &r1 );
4972 GetUpdateRect( hwnd, &r2, FALSE );
4973 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
4974 "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
4975 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
4977 DeleteObject( tmp );
4978 DeleteObject( update );
4981 static const struct message WmInvalidateRgn[] = {
4982 { WM_NCPAINT, sent },
4983 { WM_GETTEXT, sent|defwinproc|optional },
4984 { 0 }
4987 static const struct message WmGetUpdateRect[] = {
4988 { WM_NCPAINT, sent },
4989 { WM_GETTEXT, sent|defwinproc|optional },
4990 { WM_PAINT, sent },
4991 { 0 }
4994 static const struct message WmInvalidateFull[] = {
4995 { WM_NCPAINT, sent|wparam, 1 },
4996 { WM_GETTEXT, sent|defwinproc|optional },
4997 { 0 }
5000 static const struct message WmInvalidateErase[] = {
5001 { WM_NCPAINT, sent|wparam, 1 },
5002 { WM_GETTEXT, sent|defwinproc|optional },
5003 { WM_ERASEBKGND, sent },
5004 { 0 }
5007 static const struct message WmInvalidatePaint[] = {
5008 { WM_PAINT, sent },
5009 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5010 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5011 { 0 }
5014 static const struct message WmInvalidateErasePaint[] = {
5015 { WM_PAINT, sent },
5016 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5017 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5018 { WM_ERASEBKGND, sent|beginpaint },
5019 { 0 }
5022 static const struct message WmInvalidateErasePaint2[] = {
5023 { WM_PAINT, sent },
5024 { WM_NCPAINT, sent|beginpaint },
5025 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5026 { WM_ERASEBKGND, sent|beginpaint },
5027 { 0 }
5030 static const struct message WmErase[] = {
5031 { WM_ERASEBKGND, sent },
5032 { 0 }
5035 static const struct message WmPaint[] = {
5036 { WM_PAINT, sent },
5037 { 0 }
5040 static const struct message WmParentOnlyPaint[] = {
5041 { WM_PAINT, sent|parent },
5042 { 0 }
5045 static const struct message WmInvalidateParent[] = {
5046 { WM_NCPAINT, sent|parent },
5047 { WM_GETTEXT, sent|defwinproc|parent|optional },
5048 { WM_ERASEBKGND, sent|parent },
5049 { 0 }
5052 static const struct message WmInvalidateParentChild[] = {
5053 { WM_NCPAINT, sent|parent },
5054 { WM_GETTEXT, sent|defwinproc|parent|optional },
5055 { WM_ERASEBKGND, sent|parent },
5056 { WM_NCPAINT, sent },
5057 { WM_GETTEXT, sent|defwinproc|optional },
5058 { WM_ERASEBKGND, sent },
5059 { 0 }
5062 static const struct message WmInvalidateParentChild2[] = {
5063 { WM_ERASEBKGND, sent|parent },
5064 { WM_NCPAINT, sent },
5065 { WM_GETTEXT, sent|defwinproc|optional },
5066 { WM_ERASEBKGND, sent },
5067 { 0 }
5070 static const struct message WmParentPaint[] = {
5071 { WM_PAINT, sent|parent },
5072 { WM_PAINT, sent },
5073 { 0 }
5076 static const struct message WmParentPaintNc[] = {
5077 { WM_PAINT, sent|parent },
5078 { WM_PAINT, sent },
5079 { WM_NCPAINT, sent|beginpaint },
5080 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5081 { WM_ERASEBKGND, sent|beginpaint },
5082 { 0 }
5085 static const struct message WmChildPaintNc[] = {
5086 { WM_PAINT, sent },
5087 { WM_NCPAINT, sent|beginpaint },
5088 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5089 { WM_ERASEBKGND, sent|beginpaint },
5090 { 0 }
5093 static const struct message WmParentErasePaint[] = {
5094 { WM_PAINT, sent|parent },
5095 { WM_NCPAINT, sent|parent|beginpaint },
5096 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5097 { WM_ERASEBKGND, sent|parent|beginpaint },
5098 { WM_PAINT, sent },
5099 { WM_NCPAINT, sent|beginpaint },
5100 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5101 { WM_ERASEBKGND, sent|beginpaint },
5102 { 0 }
5105 static const struct message WmParentOnlyNcPaint[] = {
5106 { WM_PAINT, sent|parent },
5107 { WM_NCPAINT, sent|parent|beginpaint },
5108 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5109 { 0 }
5112 static const struct message WmSetParentStyle[] = {
5113 { WM_STYLECHANGING, sent|parent },
5114 { WM_STYLECHANGED, sent|parent },
5115 { 0 }
5118 static void test_paint_messages(void)
5120 BOOL ret;
5121 RECT rect;
5122 POINT pt;
5123 MSG msg;
5124 HWND hparent, hchild;
5125 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5126 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5127 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5128 100, 100, 200, 200, 0, 0, 0, NULL);
5129 ok (hwnd != 0, "Failed to create overlapped window\n");
5131 ShowWindow( hwnd, SW_SHOW );
5132 UpdateWindow( hwnd );
5133 flush_events();
5134 flush_sequence();
5136 check_update_rgn( hwnd, 0 );
5137 SetRectRgn( hrgn, 10, 10, 20, 20 );
5138 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5139 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5140 check_update_rgn( hwnd, hrgn );
5141 SetRectRgn( hrgn2, 20, 20, 30, 30 );
5142 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5143 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5144 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5145 check_update_rgn( hwnd, hrgn );
5146 /* validate everything */
5147 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5148 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5149 check_update_rgn( hwnd, 0 );
5151 /* test empty region */
5152 SetRectRgn( hrgn, 10, 10, 10, 15 );
5153 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5154 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5155 check_update_rgn( hwnd, 0 );
5156 /* test empty rect */
5157 SetRect( &rect, 10, 10, 10, 15 );
5158 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5159 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5160 check_update_rgn( hwnd, 0 );
5162 /* flush pending messages */
5163 flush_events();
5164 flush_sequence();
5166 GetClientRect( hwnd, &rect );
5167 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5168 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5169 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5171 trace("testing InvalidateRect(0, NULL, FALSE)\n");
5172 SetRectEmpty( &rect );
5173 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5174 check_update_rgn( hwnd, hrgn );
5175 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5176 flush_events();
5177 ok_sequence( WmPaint, "Paint", FALSE );
5178 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5179 check_update_rgn( hwnd, 0 );
5181 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5182 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5184 trace("testing ValidateRect(0, NULL)\n");
5185 SetRectEmpty( &rect );
5186 ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
5187 check_update_rgn( hwnd, hrgn );
5188 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5189 flush_events();
5190 ok_sequence( WmPaint, "Paint", FALSE );
5191 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5192 check_update_rgn( hwnd, 0 );
5194 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5195 SetLastError(0xdeadbeef);
5196 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5197 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5198 "wrong error code %d\n", GetLastError());
5199 check_update_rgn( hwnd, 0 );
5200 flush_events();
5201 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5203 trace("testing ValidateRgn(0, NULL)\n");
5204 SetLastError(0xdeadbeef);
5205 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5206 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
5207 check_update_rgn( hwnd, 0 );
5208 flush_events();
5209 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5211 /* now with frame */
5212 SetRectRgn( hrgn, -5, -5, 20, 20 );
5214 /* flush pending messages */
5215 flush_events();
5216 flush_sequence();
5217 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5218 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5220 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
5221 check_update_rgn( hwnd, hrgn );
5223 flush_sequence();
5224 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5225 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5227 flush_sequence();
5228 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5229 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5231 GetClientRect( hwnd, &rect );
5232 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5233 check_update_rgn( hwnd, hrgn );
5235 flush_sequence();
5236 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5237 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5239 flush_sequence();
5240 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5241 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5242 check_update_rgn( hwnd, 0 );
5244 flush_sequence();
5245 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5246 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5247 check_update_rgn( hwnd, 0 );
5249 flush_sequence();
5250 SetRectRgn( hrgn, 0, 0, 100, 100 );
5251 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5252 SetRectRgn( hrgn, 0, 0, 50, 100 );
5253 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5254 SetRectRgn( hrgn, 50, 0, 100, 100 );
5255 check_update_rgn( hwnd, hrgn );
5256 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5257 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
5258 check_update_rgn( hwnd, 0 );
5260 flush_sequence();
5261 SetRectRgn( hrgn, 0, 0, 100, 100 );
5262 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5263 SetRectRgn( hrgn, 0, 0, 100, 50 );
5264 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5265 ok_sequence( WmErase, "Erase", FALSE );
5266 SetRectRgn( hrgn, 0, 50, 100, 100 );
5267 check_update_rgn( hwnd, hrgn );
5269 flush_sequence();
5270 SetRectRgn( hrgn, 0, 0, 100, 100 );
5271 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5272 SetRectRgn( hrgn, 0, 0, 50, 50 );
5273 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5274 ok_sequence( WmPaint, "Paint", FALSE );
5276 flush_sequence();
5277 SetRectRgn( hrgn, -4, -4, -2, -2 );
5278 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5279 SetRectRgn( hrgn, -200, -200, -198, -198 );
5280 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5281 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5283 flush_sequence();
5284 SetRectRgn( hrgn, -4, -4, -2, -2 );
5285 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5286 SetRectRgn( hrgn, -4, -4, -3, -3 );
5287 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5288 SetRectRgn( hrgn, 0, 0, 1, 1 );
5289 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5290 ok_sequence( WmPaint, "Paint", FALSE );
5292 flush_sequence();
5293 SetRectRgn( hrgn, -4, -4, -1, -1 );
5294 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5295 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5296 /* make sure no WM_PAINT was generated */
5297 flush_events();
5298 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5300 flush_sequence();
5301 SetRectRgn( hrgn, -4, -4, -1, -1 );
5302 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5303 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5305 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5307 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5308 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5309 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5310 ret = GetUpdateRect( hwnd, &rect, FALSE );
5311 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5312 /* this will send WM_NCPAINT and validate the non client area */
5313 ret = GetUpdateRect( hwnd, &rect, TRUE );
5314 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5316 DispatchMessage( &msg );
5318 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5320 DestroyWindow( hwnd );
5322 /* now test with a child window */
5324 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5325 100, 100, 200, 200, 0, 0, 0, NULL);
5326 ok (hparent != 0, "Failed to create parent window\n");
5328 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5329 10, 10, 100, 100, hparent, 0, 0, NULL);
5330 ok (hchild != 0, "Failed to create child window\n");
5332 ShowWindow( hparent, SW_SHOW );
5333 UpdateWindow( hparent );
5334 UpdateWindow( hchild );
5335 flush_events();
5336 flush_sequence();
5337 log_all_parent_messages++;
5339 SetRect( &rect, 0, 0, 50, 50 );
5340 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5341 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5342 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5344 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5345 pt.x = pt.y = 0;
5346 MapWindowPoints( hchild, hparent, &pt, 1 );
5347 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5348 check_update_rgn( hchild, hrgn );
5349 SetRectRgn( hrgn, 0, 0, 50, 50 );
5350 check_update_rgn( hparent, hrgn );
5351 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5352 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5353 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5354 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5356 flush_events();
5357 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5359 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5360 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5361 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5362 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5363 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5365 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5366 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5367 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5369 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5370 flush_sequence();
5371 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5372 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5373 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5375 /* flush all paint messages */
5376 flush_events();
5377 flush_sequence();
5379 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5380 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5381 SetRectRgn( hrgn, 0, 0, 50, 50 );
5382 check_update_rgn( hparent, hrgn );
5383 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5384 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5385 SetRectRgn( hrgn, 0, 0, 50, 50 );
5386 check_update_rgn( hparent, hrgn );
5388 /* flush all paint messages */
5389 flush_events();
5390 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5391 flush_sequence();
5393 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5394 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5395 SetRectRgn( hrgn, 0, 0, 50, 50 );
5396 check_update_rgn( hparent, hrgn );
5397 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5398 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5399 SetRectRgn( hrgn2, 10, 10, 50, 50 );
5400 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5401 check_update_rgn( hparent, hrgn );
5402 /* flush all paint messages */
5403 flush_events();
5404 flush_sequence();
5406 /* same as above but parent gets completely validated */
5407 SetRect( &rect, 20, 20, 30, 30 );
5408 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5409 SetRectRgn( hrgn, 20, 20, 30, 30 );
5410 check_update_rgn( hparent, hrgn );
5411 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5412 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5413 check_update_rgn( hparent, 0 ); /* no update region */
5414 flush_events();
5415 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
5417 /* make sure RDW_VALIDATE on child doesn't have the same effect */
5418 flush_sequence();
5419 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5420 SetRectRgn( hrgn, 20, 20, 30, 30 );
5421 check_update_rgn( hparent, hrgn );
5422 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5423 SetRectRgn( hrgn, 20, 20, 30, 30 );
5424 check_update_rgn( hparent, hrgn );
5426 /* same as above but normal WM_PAINT doesn't validate parent */
5427 flush_sequence();
5428 SetRect( &rect, 20, 20, 30, 30 );
5429 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5430 SetRectRgn( hrgn, 20, 20, 30, 30 );
5431 check_update_rgn( hparent, hrgn );
5432 /* no WM_PAINT in child while parent still pending */
5433 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5434 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5435 while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5436 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5438 flush_sequence();
5439 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5440 /* no WM_PAINT in child while parent still pending */
5441 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5442 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5443 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5444 /* now that parent is valid child should get WM_PAINT */
5445 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5446 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5447 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5448 ok_sequence( WmEmptySeq, "No other message", FALSE );
5450 /* same thing with WS_CLIPCHILDREN in parent */
5451 flush_sequence();
5452 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5453 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5454 /* changing style invalidates non client area, but we need to invalidate something else to see it */
5455 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5456 ok_sequence( WmEmptySeq, "No message", FALSE );
5457 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5458 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5460 flush_sequence();
5461 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5462 SetRectRgn( hrgn, 20, 20, 30, 30 );
5463 check_update_rgn( hparent, hrgn );
5464 /* no WM_PAINT in child while parent still pending */
5465 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5466 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5467 /* WM_PAINT in parent first */
5468 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5469 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5471 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5472 flush_sequence();
5473 SetRect( &rect, 0, 0, 30, 30 );
5474 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5475 SetRectRgn( hrgn, 0, 0, 30, 30 );
5476 check_update_rgn( hparent, hrgn );
5477 flush_events();
5478 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5480 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5481 flush_sequence();
5482 SetRect( &rect, -10, 0, 30, 30 );
5483 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5484 SetRect( &rect, 0, 0, 20, 20 );
5485 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5486 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5487 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5489 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5490 flush_sequence();
5491 SetRect( &rect, -10, 0, 30, 30 );
5492 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5493 SetRect( &rect, 0, 0, 100, 100 );
5494 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5495 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5496 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5497 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5498 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5500 /* test RDW_INTERNALPAINT behavior */
5502 flush_sequence();
5503 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5504 flush_events();
5505 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5507 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5508 flush_events();
5509 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5511 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5512 flush_events();
5513 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5515 assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5516 UpdateWindow( hparent );
5517 flush_events();
5518 flush_sequence();
5519 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5520 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5521 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5522 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5523 flush_events();
5524 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5526 UpdateWindow( hparent );
5527 flush_events();
5528 flush_sequence();
5529 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5530 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5531 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5532 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5533 flush_events();
5534 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5536 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5537 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5538 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5539 flush_events();
5540 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5542 assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5543 UpdateWindow( hparent );
5544 flush_events();
5545 flush_sequence();
5546 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5547 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5548 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5549 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5550 flush_events();
5551 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5553 UpdateWindow( hparent );
5554 flush_events();
5555 flush_sequence();
5556 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5557 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5558 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5559 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5560 flush_events();
5561 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5563 log_all_parent_messages--;
5564 DestroyWindow( hparent );
5565 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5567 DeleteObject( hrgn );
5568 DeleteObject( hrgn2 );
5571 struct wnd_event
5573 HWND hwnd;
5574 HANDLE event;
5577 static DWORD WINAPI thread_proc(void *param)
5579 MSG msg;
5580 struct wnd_event *wnd_event = (struct wnd_event *)param;
5582 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
5583 100, 100, 200, 200, 0, 0, 0, NULL);
5584 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
5586 SetEvent(wnd_event->event);
5588 while (GetMessage(&msg, 0, 0, 0))
5590 TranslateMessage(&msg);
5591 DispatchMessage(&msg);
5594 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
5596 return 0;
5599 static void test_interthread_messages(void)
5601 HANDLE hThread;
5602 DWORD tid;
5603 WNDPROC proc;
5604 MSG msg;
5605 char buf[256];
5606 int len, expected_len;
5607 struct wnd_event wnd_event;
5608 BOOL ret;
5610 wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
5611 if (!wnd_event.event)
5613 trace("skipping interthread message test under win9x\n");
5614 return;
5617 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
5618 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
5620 ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5622 CloseHandle(wnd_event.event);
5624 SetLastError(0xdeadbeef);
5625 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
5626 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
5627 "wrong error code %d\n", GetLastError());
5629 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5630 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
5632 expected_len = lstrlenA("window caption text");
5633 memset(buf, 0, sizeof(buf));
5634 SetLastError(0xdeadbeef);
5635 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
5636 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
5637 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
5639 msg.hwnd = wnd_event.hwnd;
5640 msg.message = WM_GETTEXT;
5641 msg.wParam = sizeof(buf);
5642 msg.lParam = (LPARAM)buf;
5643 memset(buf, 0, sizeof(buf));
5644 SetLastError(0xdeadbeef);
5645 len = DispatchMessageA(&msg);
5646 ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
5647 "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
5649 /* the following test causes an exception in user.exe under win9x */
5650 msg.hwnd = wnd_event.hwnd;
5651 msg.message = WM_TIMER;
5652 msg.wParam = 0;
5653 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5654 SetLastError(0xdeadbeef);
5655 len = DispatchMessageA(&msg);
5656 ok(!len && GetLastError() == 0xdeadbeef,
5657 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
5659 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
5660 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
5662 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5663 CloseHandle(hThread);
5665 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
5669 static const struct message WmVkN[] = {
5670 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5671 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5672 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5673 { WM_CHAR, wparam|lparam, 'n', 1 },
5674 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
5675 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5676 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5677 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5678 { 0 }
5680 static const struct message WmShiftVkN[] = {
5681 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5682 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5683 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5684 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5685 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5686 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5687 { WM_CHAR, wparam|lparam, 'N', 1 },
5688 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
5689 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5690 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5691 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5692 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5693 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5694 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5695 { 0 }
5697 static const struct message WmCtrlVkN[] = {
5698 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5699 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5700 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5701 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5702 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5703 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5704 { WM_CHAR, wparam|lparam, 0x000e, 1 },
5705 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5706 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5707 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5708 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5709 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5710 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5711 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5712 { 0 }
5714 static const struct message WmCtrlVkN_2[] = {
5715 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5716 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5717 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5718 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5719 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5720 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5721 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5722 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5723 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5724 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5725 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5726 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5727 { 0 }
5729 static const struct message WmAltVkN[] = {
5730 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5731 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5732 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5733 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5734 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5735 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5736 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
5737 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
5738 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
5739 { HCBT_SYSCOMMAND, hook },
5740 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5741 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5742 { 0x00AE, sent|defwinproc|optional }, /* XP */
5743 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
5744 { WM_INITMENU, sent|defwinproc },
5745 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5746 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
5747 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5748 { WM_CAPTURECHANGED, sent|defwinproc },
5749 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
5750 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5751 { WM_EXITMENULOOP, sent|defwinproc },
5752 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
5753 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
5754 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5755 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5756 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5757 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5758 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5759 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5760 { 0 }
5762 static const struct message WmAltVkN_2[] = {
5763 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5764 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5765 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5766 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5767 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5768 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
5769 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5770 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5771 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5772 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5773 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5774 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5775 { 0 }
5777 static const struct message WmCtrlAltVkN[] = {
5778 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5779 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5780 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5781 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5782 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5783 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5784 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5785 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5786 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5787 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5788 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5789 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5790 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5791 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5792 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5793 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5794 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5795 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5796 { 0 }
5798 static const struct message WmCtrlShiftVkN[] = {
5799 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5800 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5801 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5802 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5803 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5804 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5805 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5806 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5807 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
5808 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5809 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5810 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5811 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5812 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5813 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5814 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5815 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5816 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5817 { 0 }
5819 static const struct message WmCtrlAltShiftVkN[] = {
5820 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5821 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5822 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5823 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5824 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5825 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5826 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
5827 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
5828 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
5829 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5830 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5831 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
5832 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5833 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5834 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5835 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
5836 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
5837 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
5838 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5839 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5840 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5841 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5842 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5843 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5844 { 0 }
5846 static const struct message WmAltPressRelease[] = {
5847 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5848 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5849 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5850 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5851 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5852 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5853 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
5854 { HCBT_SYSCOMMAND, hook },
5855 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5856 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5857 { WM_INITMENU, sent|defwinproc },
5858 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5859 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
5860 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
5862 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
5864 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5865 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
5866 { WM_CAPTURECHANGED, sent|defwinproc },
5867 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
5868 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5869 { WM_EXITMENULOOP, sent|defwinproc },
5870 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5871 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5872 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5873 { 0 }
5875 static const struct message WmAltMouseButton[] = {
5876 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5877 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5878 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5879 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
5880 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
5881 { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
5882 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
5883 { WM_LBUTTONUP, wparam, 0, 0 },
5884 { WM_LBUTTONUP, sent|wparam, 0, 0 },
5885 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5886 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5887 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5888 { 0 }
5890 static const struct message WmF1Seq[] = {
5891 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
5892 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
5893 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
5894 { 0x4d, wparam|lparam, 0, 0 },
5895 { 0x4d, sent|wparam|lparam, 0, 0 },
5896 { WM_HELP, sent|defwinproc },
5897 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
5898 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
5899 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
5900 { 0 }
5902 static const struct message WmVkAppsSeq[] = {
5903 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
5904 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
5905 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
5906 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
5907 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
5908 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
5909 { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
5910 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
5911 { 0 }
5914 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
5916 MSG msg;
5918 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
5920 struct message log_msg;
5922 trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
5924 /* ignore some unwanted messages */
5925 if (msg.message == WM_MOUSEMOVE ||
5926 msg.message == WM_GETICON ||
5927 msg.message == WM_DEVICECHANGE)
5928 continue;
5930 log_msg.message = msg.message;
5931 log_msg.flags = wparam|lparam;
5932 log_msg.wParam = msg.wParam;
5933 log_msg.lParam = msg.lParam;
5934 add_message(&log_msg);
5936 if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
5938 TranslateMessage(&msg);
5939 DispatchMessage(&msg);
5944 static void test_accelerators(void)
5946 RECT rc;
5947 SHORT state;
5948 HACCEL hAccel;
5949 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5950 100, 100, 200, 200, 0, 0, 0, NULL);
5951 BOOL ret;
5953 assert(hwnd != 0);
5954 UpdateWindow(hwnd);
5955 flush_events();
5956 flush_sequence();
5958 SetFocus(hwnd);
5959 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
5961 state = GetKeyState(VK_SHIFT);
5962 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
5963 state = GetKeyState(VK_CAPITAL);
5964 ok(state == 0, "wrong CapsLock state %04x\n", state);
5966 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
5967 assert(hAccel != 0);
5969 pump_msg_loop(hwnd, 0);
5970 flush_sequence();
5972 trace("testing VK_N press/release\n");
5973 flush_sequence();
5974 keybd_event('N', 0, 0, 0);
5975 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5976 pump_msg_loop(hwnd, hAccel);
5977 ok_sequence(WmVkN, "VK_N press/release", FALSE);
5979 trace("testing Shift+VK_N press/release\n");
5980 flush_sequence();
5981 keybd_event(VK_SHIFT, 0, 0, 0);
5982 keybd_event('N', 0, 0, 0);
5983 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5984 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5985 pump_msg_loop(hwnd, hAccel);
5986 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
5988 trace("testing Ctrl+VK_N press/release\n");
5989 flush_sequence();
5990 keybd_event(VK_CONTROL, 0, 0, 0);
5991 keybd_event('N', 0, 0, 0);
5992 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5993 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5994 pump_msg_loop(hwnd, hAccel);
5995 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
5997 trace("testing Alt+VK_N press/release\n");
5998 flush_sequence();
5999 keybd_event(VK_MENU, 0, 0, 0);
6000 keybd_event('N', 0, 0, 0);
6001 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6002 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6003 pump_msg_loop(hwnd, hAccel);
6004 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6006 trace("testing Ctrl+Alt+VK_N press/release 1\n");
6007 flush_sequence();
6008 keybd_event(VK_CONTROL, 0, 0, 0);
6009 keybd_event(VK_MENU, 0, 0, 0);
6010 keybd_event('N', 0, 0, 0);
6011 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6012 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6013 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6014 pump_msg_loop(hwnd, hAccel);
6015 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6017 ret = DestroyAcceleratorTable(hAccel);
6018 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6020 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6021 assert(hAccel != 0);
6023 trace("testing VK_N press/release\n");
6024 flush_sequence();
6025 keybd_event('N', 0, 0, 0);
6026 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6027 pump_msg_loop(hwnd, hAccel);
6028 ok_sequence(WmVkN, "VK_N press/release", FALSE);
6030 trace("testing Shift+VK_N press/release\n");
6031 flush_sequence();
6032 keybd_event(VK_SHIFT, 0, 0, 0);
6033 keybd_event('N', 0, 0, 0);
6034 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6035 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6036 pump_msg_loop(hwnd, hAccel);
6037 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6039 trace("testing Ctrl+VK_N press/release 2\n");
6040 flush_sequence();
6041 keybd_event(VK_CONTROL, 0, 0, 0);
6042 keybd_event('N', 0, 0, 0);
6043 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6044 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6045 pump_msg_loop(hwnd, hAccel);
6046 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6048 trace("testing Alt+VK_N press/release 2\n");
6049 flush_sequence();
6050 keybd_event(VK_MENU, 0, 0, 0);
6051 keybd_event('N', 0, 0, 0);
6052 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6053 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6054 pump_msg_loop(hwnd, hAccel);
6055 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6057 trace("testing Ctrl+Alt+VK_N press/release 2\n");
6058 flush_sequence();
6059 keybd_event(VK_CONTROL, 0, 0, 0);
6060 keybd_event(VK_MENU, 0, 0, 0);
6061 keybd_event('N', 0, 0, 0);
6062 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6063 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6064 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6065 pump_msg_loop(hwnd, hAccel);
6066 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6068 trace("testing Ctrl+Shift+VK_N press/release\n");
6069 flush_sequence();
6070 keybd_event(VK_CONTROL, 0, 0, 0);
6071 keybd_event(VK_SHIFT, 0, 0, 0);
6072 keybd_event('N', 0, 0, 0);
6073 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6074 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6075 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6076 pump_msg_loop(hwnd, hAccel);
6077 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6079 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6080 flush_sequence();
6081 keybd_event(VK_CONTROL, 0, 0, 0);
6082 keybd_event(VK_MENU, 0, 0, 0);
6083 keybd_event(VK_SHIFT, 0, 0, 0);
6084 keybd_event('N', 0, 0, 0);
6085 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6086 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6087 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6088 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6089 pump_msg_loop(hwnd, hAccel);
6090 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6092 ret = DestroyAcceleratorTable(hAccel);
6093 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6095 trace("testing Alt press/release\n");
6096 flush_sequence();
6097 keybd_event(VK_MENU, 0, 0, 0);
6098 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6099 keybd_event(VK_MENU, 0, 0, 0);
6100 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6101 pump_msg_loop(hwnd, 0);
6102 /* this test doesn't pass in Wine for managed windows */
6103 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6105 trace("testing Alt+MouseButton press/release\n");
6106 /* first, move mouse pointer inside of the window client area */
6107 GetClientRect(hwnd, &rc);
6108 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6109 rc.left += (rc.right - rc.left)/2;
6110 rc.top += (rc.bottom - rc.top)/2;
6111 SetCursorPos(rc.left, rc.top);
6113 flush_events();
6114 flush_sequence();
6115 keybd_event(VK_MENU, 0, 0, 0);
6116 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6117 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6118 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6119 pump_msg_loop(hwnd, 0);
6120 ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
6122 trace("testing VK_F1 press/release\n");
6123 keybd_event(VK_F1, 0, 0, 0);
6124 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6125 pump_msg_loop(hwnd, 0);
6126 ok_sequence(WmF1Seq, "F1 press/release", TRUE);
6128 trace("testing VK_APPS press/release\n");
6129 keybd_event(VK_APPS, 0, 0, 0);
6130 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6131 pump_msg_loop(hwnd, 0);
6132 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6134 DestroyWindow(hwnd);
6137 /************* window procedures ********************/
6139 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
6140 WPARAM wParam, LPARAM lParam)
6142 static long defwndproc_counter = 0;
6143 static long beginpaint_counter = 0;
6144 LRESULT ret;
6145 struct message msg;
6147 trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6149 /* explicitly ignore WM_GETICON message */
6150 if (message == WM_GETICON) return 0;
6152 switch (message)
6154 case WM_ENABLE:
6156 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6157 ok((BOOL)wParam == !(style & WS_DISABLED),
6158 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6159 break;
6162 case WM_CAPTURECHANGED:
6163 if (test_DestroyWindow_flag)
6165 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6166 if (style & WS_CHILD)
6167 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6168 else if (style & WS_POPUP)
6169 lParam = WND_POPUP_ID;
6170 else
6171 lParam = WND_PARENT_ID;
6173 break;
6175 case WM_NCDESTROY:
6177 HWND capture;
6179 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6180 capture = GetCapture();
6181 if (capture)
6183 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6184 trace("current capture %p, releasing...\n", capture);
6185 ReleaseCapture();
6188 /* fall through */
6189 case WM_DESTROY:
6190 if (pGetAncestor)
6191 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6192 if (test_DestroyWindow_flag)
6194 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6195 if (style & WS_CHILD)
6196 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6197 else if (style & WS_POPUP)
6198 lParam = WND_POPUP_ID;
6199 else
6200 lParam = WND_PARENT_ID;
6202 break;
6204 /* test_accelerators() depends on this */
6205 case WM_NCHITTEST:
6206 return HTCLIENT;
6208 /* ignore */
6209 case WM_MOUSEMOVE:
6210 case WM_SETCURSOR:
6211 case WM_DEVICECHANGE:
6212 return 0;
6214 case WM_WINDOWPOSCHANGING:
6215 case WM_WINDOWPOSCHANGED:
6217 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6219 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6220 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6221 winpos->hwnd, winpos->hwndInsertAfter,
6222 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6223 dump_winpos_flags(winpos->flags);
6225 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6226 * in the high word for internal purposes
6228 wParam = winpos->flags & 0xffff;
6229 /* We are not interested in the flags that don't match under XP and Win9x */
6230 wParam &= ~(SWP_NOZORDER);
6231 break;
6235 msg.message = message;
6236 msg.flags = sent|wparam|lparam;
6237 if (defwndproc_counter) msg.flags |= defwinproc;
6238 if (beginpaint_counter) msg.flags |= beginpaint;
6239 msg.wParam = wParam;
6240 msg.lParam = lParam;
6241 add_message(&msg);
6243 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6245 HWND parent = GetParent(hwnd);
6246 RECT rc;
6247 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6249 GetClientRect(parent, &rc);
6250 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6252 trace("ptReserved = (%d,%d)\n"
6253 "ptMaxSize = (%d,%d)\n"
6254 "ptMaxPosition = (%d,%d)\n"
6255 "ptMinTrackSize = (%d,%d)\n"
6256 "ptMaxTrackSize = (%d,%d)\n",
6257 minmax->ptReserved.x, minmax->ptReserved.y,
6258 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6259 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6260 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6261 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6263 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6264 minmax->ptMaxSize.x, rc.right);
6265 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6266 minmax->ptMaxSize.y, rc.bottom);
6269 if (message == WM_PAINT)
6271 PAINTSTRUCT ps;
6272 beginpaint_counter++;
6273 BeginPaint( hwnd, &ps );
6274 beginpaint_counter--;
6275 EndPaint( hwnd, &ps );
6276 return 0;
6279 defwndproc_counter++;
6280 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
6281 : DefWindowProcA(hwnd, message, wParam, lParam);
6282 defwndproc_counter--;
6284 return ret;
6287 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6289 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6292 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6294 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6297 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6299 static long defwndproc_counter = 0;
6300 LRESULT ret;
6301 struct message msg;
6303 trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6305 /* explicitly ignore WM_GETICON message */
6306 if (message == WM_GETICON) return 0;
6308 msg.message = message;
6309 msg.flags = sent|wparam|lparam;
6310 if (defwndproc_counter) msg.flags |= defwinproc;
6311 msg.wParam = wParam;
6312 msg.lParam = lParam;
6313 add_message(&msg);
6315 if (message == WM_CREATE)
6317 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6318 SetWindowLongA(hwnd, GWL_STYLE, style);
6321 defwndproc_counter++;
6322 ret = DefWindowProcA(hwnd, message, wParam, lParam);
6323 defwndproc_counter--;
6325 return ret;
6328 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6330 static long defwndproc_counter = 0;
6331 static long beginpaint_counter = 0;
6332 LRESULT ret;
6333 struct message msg;
6334 LPARAM logged_lParam;
6336 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6338 /* explicitly ignore WM_GETICON message */
6339 if (message == WM_GETICON) return 0;
6341 logged_lParam=lParam;
6342 if (log_all_parent_messages ||
6343 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
6344 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
6345 message == WM_ENABLE || message == WM_ENTERIDLE ||
6346 message == WM_DRAWITEM ||
6347 message == WM_IME_SETCONTEXT)
6349 switch (message)
6351 /* ignore */
6352 case WM_NCHITTEST:
6353 return HTCLIENT;
6354 case WM_SETCURSOR:
6355 case WM_MOUSEMOVE:
6356 return 0;
6358 case WM_ERASEBKGND:
6360 RECT rc;
6361 INT ret = GetClipBox((HDC)wParam, &rc);
6363 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
6364 ret, rc.left, rc.top, rc.right, rc.bottom);
6365 break;
6368 case WM_WINDOWPOSCHANGING:
6369 case WM_WINDOWPOSCHANGED:
6371 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6373 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6374 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6375 winpos->hwnd, winpos->hwndInsertAfter,
6376 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6377 dump_winpos_flags(winpos->flags);
6379 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6380 * in the high word for internal purposes
6382 wParam = winpos->flags & 0xffff;
6383 /* We are not interested in the flags that don't match under XP and Win9x */
6384 wParam &= ~(SWP_NOZORDER);
6385 break;
6388 case WM_DRAWITEM:
6390 /* encode DRAWITEMSTRUCT into an LPARAM */
6391 DRAW_ITEM_STRUCT di;
6392 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
6394 trace("WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x\n",
6395 dis->CtlType, dis->CtlID, dis->itemID, dis->itemAction, dis->itemState);
6397 di.u.item.type = dis->CtlType;
6398 di.u.item.ctl_id = dis->CtlID;
6399 di.u.item.item_id = dis->itemID;
6400 di.u.item.action = dis->itemAction;
6401 di.u.item.state = dis->itemState;
6403 logged_lParam = di.u.lp;
6404 break;
6408 msg.message = message;
6409 msg.flags = sent|parent|wparam|lparam;
6410 if (defwndproc_counter) msg.flags |= defwinproc;
6411 if (beginpaint_counter) msg.flags |= beginpaint;
6412 msg.wParam = wParam;
6413 msg.lParam = logged_lParam;
6414 add_message(&msg);
6417 if (message == WM_PAINT)
6419 PAINTSTRUCT ps;
6420 beginpaint_counter++;
6421 BeginPaint( hwnd, &ps );
6422 beginpaint_counter--;
6423 EndPaint( hwnd, &ps );
6424 return 0;
6427 defwndproc_counter++;
6428 ret = DefWindowProcA(hwnd, message, wParam, lParam);
6429 defwndproc_counter--;
6431 return ret;
6434 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6436 static long defwndproc_counter = 0;
6437 LRESULT ret;
6438 struct message msg;
6440 trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6442 /* explicitly ignore WM_GETICON message */
6443 if (message == WM_GETICON) return 0;
6445 if (test_def_id)
6447 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6448 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6449 if (after_end_dialog)
6450 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6451 else
6452 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6455 switch (message)
6457 case WM_WINDOWPOSCHANGING:
6458 case WM_WINDOWPOSCHANGED:
6460 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6462 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6463 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6464 winpos->hwnd, winpos->hwndInsertAfter,
6465 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6466 dump_winpos_flags(winpos->flags);
6468 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6469 * in the high word for internal purposes
6471 wParam = winpos->flags & 0xffff;
6472 /* We are not interested in the flags that don't match under XP and Win9x */
6473 wParam &= ~(SWP_NOZORDER);
6474 break;
6478 msg.message = message;
6479 msg.flags = sent|wparam|lparam;
6480 if (defwndproc_counter) msg.flags |= defwinproc;
6481 msg.wParam = wParam;
6482 msg.lParam = lParam;
6483 add_message(&msg);
6485 defwndproc_counter++;
6486 ret = DefDlgProcA(hwnd, message, wParam, lParam);
6487 defwndproc_counter--;
6489 return ret;
6492 static void dump_winpos_flags(UINT flags)
6494 if (!winetest_debug) return;
6496 if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
6497 if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
6498 if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
6499 if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
6500 if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
6501 if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
6502 if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
6503 if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
6504 if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
6505 if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
6506 if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
6507 if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
6508 if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
6509 if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
6510 if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
6512 #define DUMPED_FLAGS \
6513 (SWP_NOSIZE | \
6514 SWP_NOMOVE | \
6515 SWP_NOZORDER | \
6516 SWP_NOREDRAW | \
6517 SWP_NOACTIVATE | \
6518 SWP_FRAMECHANGED | \
6519 SWP_SHOWWINDOW | \
6520 SWP_HIDEWINDOW | \
6521 SWP_NOCOPYBITS | \
6522 SWP_NOOWNERZORDER | \
6523 SWP_NOSENDCHANGING | \
6524 SWP_DEFERERASE | \
6525 SWP_ASYNCWINDOWPOS | \
6526 SWP_NOCLIENTSIZE | \
6527 SWP_NOCLIENTMOVE)
6529 if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
6530 printf("\n");
6531 #undef DUMPED_FLAGS
6534 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6536 static long defwndproc_counter = 0;
6537 LRESULT ret;
6538 struct message msg;
6540 /* log only specific messages we are interested in */
6541 switch (message)
6543 #if 0 /* probably log these as well */
6544 case WM_ACTIVATE:
6545 case WM_SETFOCUS:
6546 case WM_KILLFOCUS:
6547 #endif
6548 case WM_SHOWWINDOW:
6549 trace("WM_SHOWWINDOW %ld\n", wParam);
6550 break;
6551 case WM_SIZE:
6552 trace("WM_SIZE %ld\n", wParam);
6553 break;
6554 case WM_MOVE:
6555 trace("WM_MOVE\n");
6556 break;
6557 case WM_GETMINMAXINFO:
6558 trace("WM_GETMINMAXINFO\n");
6559 break;
6561 case WM_WINDOWPOSCHANGING:
6562 case WM_WINDOWPOSCHANGED:
6564 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6566 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6567 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6568 winpos->hwnd, winpos->hwndInsertAfter,
6569 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6570 trace("flags: ");
6571 dump_winpos_flags(winpos->flags);
6573 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6574 * in the high word for internal purposes
6576 wParam = winpos->flags & 0xffff;
6577 /* We are not interested in the flags that don't match under XP and Win9x */
6578 wParam &= ~(SWP_NOZORDER);
6579 break;
6582 default: /* ignore */
6583 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
6584 return DefWindowProcA(hwnd, message, wParam, lParam);
6587 msg.message = message;
6588 msg.flags = sent|wparam|lparam;
6589 if (defwndproc_counter) msg.flags |= defwinproc;
6590 msg.wParam = wParam;
6591 msg.lParam = lParam;
6592 add_message(&msg);
6594 defwndproc_counter++;
6595 ret = DefWindowProcA(hwnd, message, wParam, lParam);
6596 defwndproc_counter--;
6598 return ret;
6601 static BOOL RegisterWindowClasses(void)
6603 WNDCLASSA cls;
6604 WNDCLASSW clsW;
6606 cls.style = 0;
6607 cls.lpfnWndProc = MsgCheckProcA;
6608 cls.cbClsExtra = 0;
6609 cls.cbWndExtra = 0;
6610 cls.hInstance = GetModuleHandleA(0);
6611 cls.hIcon = 0;
6612 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
6613 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6614 cls.lpszMenuName = NULL;
6615 cls.lpszClassName = "TestWindowClass";
6616 if(!RegisterClassA(&cls)) return FALSE;
6618 cls.lpfnWndProc = ShowWindowProcA;
6619 cls.lpszClassName = "ShowWindowClass";
6620 if(!RegisterClassA(&cls)) return FALSE;
6622 cls.lpfnWndProc = PopupMsgCheckProcA;
6623 cls.lpszClassName = "TestPopupClass";
6624 if(!RegisterClassA(&cls)) return FALSE;
6626 cls.lpfnWndProc = ParentMsgCheckProcA;
6627 cls.lpszClassName = "TestParentClass";
6628 if(!RegisterClassA(&cls)) return FALSE;
6630 cls.lpfnWndProc = DefWindowProcA;
6631 cls.lpszClassName = "SimpleWindowClass";
6632 if(!RegisterClassA(&cls)) return FALSE;
6634 cls.style = CS_NOCLOSE;
6635 cls.lpszClassName = "NoCloseWindowClass";
6636 if(!RegisterClassA(&cls)) return FALSE;
6638 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
6639 cls.style = 0;
6640 cls.hInstance = GetModuleHandleA(0);
6641 cls.hbrBackground = 0;
6642 cls.lpfnWndProc = TestDlgProcA;
6643 cls.lpszClassName = "TestDialogClass";
6644 if(!RegisterClassA(&cls)) return FALSE;
6646 clsW.style = 0;
6647 clsW.lpfnWndProc = MsgCheckProcW;
6648 clsW.cbClsExtra = 0;
6649 clsW.cbWndExtra = 0;
6650 clsW.hInstance = GetModuleHandleW(0);
6651 clsW.hIcon = 0;
6652 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
6653 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
6654 clsW.lpszMenuName = NULL;
6655 clsW.lpszClassName = testWindowClassW;
6656 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
6658 return TRUE;
6661 static HHOOK hCBT_hook;
6662 static DWORD cbt_hook_thread_id;
6664 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
6666 static const char * const CBT_code_name[10] = {
6667 "HCBT_MOVESIZE",
6668 "HCBT_MINMAX",
6669 "HCBT_QS",
6670 "HCBT_CREATEWND",
6671 "HCBT_DESTROYWND",
6672 "HCBT_ACTIVATE",
6673 "HCBT_CLICKSKIPPED",
6674 "HCBT_KEYSKIPPED",
6675 "HCBT_SYSCOMMAND",
6676 "HCBT_SETFOCUS" };
6677 const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
6678 HWND hwnd;
6679 char buf[256];
6681 trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
6683 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6685 if (nCode == HCBT_CLICKSKIPPED)
6687 /* ignore this event, XP sends it a lot when switching focus between windows */
6688 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6691 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
6693 struct message msg;
6695 msg.message = nCode;
6696 msg.flags = hook|wparam|lparam;
6697 msg.wParam = wParam;
6698 msg.lParam = lParam;
6699 add_message(&msg);
6701 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6704 if (nCode == HCBT_DESTROYWND)
6706 if (test_DestroyWindow_flag)
6708 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
6709 if (style & WS_CHILD)
6710 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
6711 else if (style & WS_POPUP)
6712 lParam = WND_POPUP_ID;
6713 else
6714 lParam = WND_PARENT_ID;
6718 /* Log also SetFocus(0) calls */
6719 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6721 if (GetClassNameA(hwnd, buf, sizeof(buf)))
6723 if (!lstrcmpiA(buf, "TestWindowClass") ||
6724 !lstrcmpiA(buf, "ShowWindowClass") ||
6725 !lstrcmpiA(buf, "TestParentClass") ||
6726 !lstrcmpiA(buf, "TestPopupClass") ||
6727 !lstrcmpiA(buf, "SimpleWindowClass") ||
6728 !lstrcmpiA(buf, "TestDialogClass") ||
6729 !lstrcmpiA(buf, "MDI_frame_class") ||
6730 !lstrcmpiA(buf, "MDI_client_class") ||
6731 !lstrcmpiA(buf, "MDI_child_class") ||
6732 !lstrcmpiA(buf, "my_button_class") ||
6733 !lstrcmpiA(buf, "my_edit_class") ||
6734 !lstrcmpiA(buf, "static") ||
6735 !lstrcmpiA(buf, "ListBox") ||
6736 !lstrcmpiA(buf, "MyDialogClass") ||
6737 !lstrcmpiA(buf, "#32770"))
6739 struct message msg;
6741 msg.message = nCode;
6742 msg.flags = hook|wparam|lparam;
6743 msg.wParam = wParam;
6744 msg.lParam = lParam;
6745 add_message(&msg);
6748 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6751 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
6752 DWORD event,
6753 HWND hwnd,
6754 LONG object_id,
6755 LONG child_id,
6756 DWORD thread_id,
6757 DWORD event_time)
6759 char buf[256];
6761 trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6762 hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6764 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6766 /* ignore mouse cursor events */
6767 if (object_id == OBJID_CURSOR) return;
6769 if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
6771 if (!hwnd ||
6772 !lstrcmpiA(buf, "TestWindowClass") ||
6773 !lstrcmpiA(buf, "TestParentClass") ||
6774 !lstrcmpiA(buf, "TestPopupClass") ||
6775 !lstrcmpiA(buf, "SimpleWindowClass") ||
6776 !lstrcmpiA(buf, "TestDialogClass") ||
6777 !lstrcmpiA(buf, "MDI_frame_class") ||
6778 !lstrcmpiA(buf, "MDI_client_class") ||
6779 !lstrcmpiA(buf, "MDI_child_class") ||
6780 !lstrcmpiA(buf, "my_button_class") ||
6781 !lstrcmpiA(buf, "my_edit_class") ||
6782 !lstrcmpiA(buf, "static") ||
6783 !lstrcmpiA(buf, "ListBox") ||
6784 !lstrcmpiA(buf, "MyDialogClass") ||
6785 !lstrcmpiA(buf, "#32770"))
6787 struct message msg;
6789 msg.message = event;
6790 msg.flags = winevent_hook|wparam|lparam;
6791 msg.wParam = object_id;
6792 msg.lParam = child_id;
6793 add_message(&msg);
6798 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
6799 static const WCHAR wszAnsi[] = {'U',0};
6801 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6803 switch (uMsg)
6805 case CB_FINDSTRINGEXACT:
6806 trace("String: %p\n", (LPCWSTR)lParam);
6807 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
6808 return 1;
6809 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
6810 return 0;
6811 return -1;
6813 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
6816 static const struct message WmGetTextLengthAfromW[] = {
6817 { WM_GETTEXTLENGTH, sent },
6818 { WM_GETTEXT, sent },
6819 { 0 }
6822 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
6824 /* dummy window proc for WM_GETTEXTLENGTH test */
6825 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
6827 switch(msg)
6829 case WM_GETTEXTLENGTH:
6830 return lstrlenW(dummy_window_text) + 37; /* some random length */
6831 case WM_GETTEXT:
6832 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
6833 return lstrlenW( (LPWSTR)lp );
6834 default:
6835 return DefWindowProcW( hwnd, msg, wp, lp );
6839 static void test_message_conversion(void)
6841 static const WCHAR wszMsgConversionClass[] =
6842 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
6843 WNDCLASSW cls;
6844 LRESULT lRes;
6845 HWND hwnd;
6846 WNDPROC wndproc, newproc;
6847 BOOL ret;
6849 cls.style = 0;
6850 cls.lpfnWndProc = MsgConversionProcW;
6851 cls.cbClsExtra = 0;
6852 cls.cbWndExtra = 0;
6853 cls.hInstance = GetModuleHandleW(NULL);
6854 cls.hIcon = NULL;
6855 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
6856 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
6857 cls.lpszMenuName = NULL;
6858 cls.lpszClassName = wszMsgConversionClass;
6859 /* this call will fail on Win9x, but that doesn't matter as this test is
6860 * meaningless on those platforms */
6861 if(!RegisterClassW(&cls)) return;
6863 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
6864 100, 100, 200, 200, 0, 0, 0, NULL);
6865 ok(hwnd != NULL, "Window creation failed\n");
6867 /* {W, A} -> A */
6869 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
6870 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6871 ok(lRes == 0, "String should have been converted\n");
6872 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6873 ok(lRes == 1, "String shouldn't have been converted\n");
6875 /* {W, A} -> W */
6877 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
6878 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6879 ok(lRes == 1, "String shouldn't have been converted\n");
6880 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6881 ok(lRes == 1, "String shouldn't have been converted\n");
6883 /* Synchronous messages */
6885 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6886 ok(lRes == 0, "String should have been converted\n");
6887 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6888 ok(lRes == 1, "String shouldn't have been converted\n");
6890 /* Asynchronous messages */
6892 SetLastError(0);
6893 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6894 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6895 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6896 SetLastError(0);
6897 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6898 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6899 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6900 SetLastError(0);
6901 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6902 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6903 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6904 SetLastError(0);
6905 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6906 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6907 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6908 SetLastError(0);
6909 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6910 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6911 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6912 SetLastError(0);
6913 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6914 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6915 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6916 SetLastError(0);
6917 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6918 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6919 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6920 SetLastError(0);
6921 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6922 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6923 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6925 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
6927 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
6928 WS_OVERLAPPEDWINDOW,
6929 100, 100, 200, 200, 0, 0, 0, NULL);
6930 assert(hwnd);
6931 flush_sequence();
6932 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
6933 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6934 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6935 "got bad length %ld\n", lRes );
6937 flush_sequence();
6938 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
6939 hwnd, WM_GETTEXTLENGTH, 0, 0);
6940 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6941 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6942 "got bad length %ld\n", lRes );
6944 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
6945 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
6946 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6947 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6948 NULL, 0, NULL, NULL ),
6949 "got bad length %ld\n", lRes );
6951 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
6952 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6953 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6954 NULL, 0, NULL, NULL ),
6955 "got bad length %ld\n", lRes );
6957 ret = DestroyWindow(hwnd);
6958 ok( ret, "DestroyWindow() error %d\n", GetLastError());
6961 struct timer_info
6963 HWND hWnd;
6964 HANDLE handles[2];
6965 DWORD id;
6968 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
6972 #define TIMER_ID 0x19
6974 static DWORD WINAPI timer_thread_proc(LPVOID x)
6976 struct timer_info *info = x;
6977 DWORD r;
6979 r = KillTimer(info->hWnd, 0x19);
6980 ok(r,"KillTimer failed in thread\n");
6981 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
6982 ok(r,"SetTimer failed in thread\n");
6983 ok(r==TIMER_ID,"SetTimer id different\n");
6984 r = SetEvent(info->handles[0]);
6985 ok(r,"SetEvent failed in thread\n");
6986 return 0;
6989 static void test_timers(void)
6991 struct timer_info info;
6992 DWORD id;
6994 info.hWnd = CreateWindow ("TestWindowClass", NULL,
6995 WS_OVERLAPPEDWINDOW ,
6996 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6997 NULL, NULL, 0);
6999 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7000 ok(info.id, "SetTimer failed\n");
7001 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7002 info.handles[0] = CreateEvent(NULL,0,0,NULL);
7003 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7005 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7007 WaitForSingleObject(info.handles[1], INFINITE);
7009 CloseHandle(info.handles[0]);
7010 CloseHandle(info.handles[1]);
7012 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7014 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7017 static int count = 0;
7018 static VOID CALLBACK callback_count(
7019 HWND hwnd,
7020 UINT uMsg,
7021 UINT_PTR idEvent,
7022 DWORD dwTime
7025 count++;
7028 static void test_timers_no_wnd(void)
7030 UINT_PTR id, id2;
7031 MSG msg;
7033 count = 0;
7034 id = SetTimer(NULL, 0, 100, callback_count);
7035 ok(id != 0, "did not get id from SetTimer.\n");
7036 id2 = SetTimer(NULL, id, 200, callback_count);
7037 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7038 Sleep(150);
7039 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7040 ok(count == 0, "did not get zero count as expected (%i).\n", count);
7041 Sleep(150);
7042 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7043 ok(count == 1, "did not get one count as expected (%i).\n", count);
7044 KillTimer(NULL, id);
7045 Sleep(250);
7046 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7047 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7050 /* Various win events with arbitrary parameters */
7051 static const struct message WmWinEventsSeq[] = {
7052 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7053 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7054 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7055 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7056 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7057 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7058 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7059 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7060 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7061 /* our win event hook ignores OBJID_CURSOR events */
7062 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7063 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7064 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7065 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7066 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7067 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7068 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7069 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7070 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7071 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7072 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7073 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7074 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7075 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7076 { 0 }
7078 static const struct message WmWinEventCaretSeq[] = {
7079 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7080 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7081 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7082 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7083 { 0 }
7085 static const struct message WmWinEventCaretSeq_2[] = {
7086 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7087 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7088 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7089 { 0 }
7091 static const struct message WmWinEventAlertSeq[] = {
7092 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7093 { 0 }
7095 static const struct message WmWinEventAlertSeq_2[] = {
7096 /* create window in the thread proc */
7097 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7098 /* our test event */
7099 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7100 { 0 }
7102 static const struct message WmGlobalHookSeq_1[] = {
7103 /* create window in the thread proc */
7104 { HCBT_CREATEWND, hook|lparam, 0, 2 },
7105 /* our test events */
7106 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7107 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7108 { 0 }
7110 static const struct message WmGlobalHookSeq_2[] = {
7111 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7112 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7113 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7114 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7115 { 0 }
7118 static const struct message WmMouseLLHookSeq[] = {
7119 { WM_MOUSEMOVE, hook },
7120 { WM_LBUTTONUP, hook },
7121 { WM_MOUSEMOVE, hook },
7122 { 0 }
7125 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7126 DWORD event,
7127 HWND hwnd,
7128 LONG object_id,
7129 LONG child_id,
7130 DWORD thread_id,
7131 DWORD event_time)
7133 char buf[256];
7135 trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7136 hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7138 if (GetClassNameA(hwnd, buf, sizeof(buf)))
7140 if (!lstrcmpiA(buf, "TestWindowClass") ||
7141 !lstrcmpiA(buf, "static"))
7143 struct message msg;
7145 msg.message = event;
7146 msg.flags = winevent_hook|wparam|lparam;
7147 msg.wParam = object_id;
7148 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7149 add_message(&msg);
7154 static HHOOK hCBT_global_hook;
7155 static DWORD cbt_global_hook_thread_id;
7157 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
7159 HWND hwnd;
7160 char buf[256];
7162 trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam);
7164 if (nCode == HCBT_SYSCOMMAND)
7166 struct message msg;
7168 msg.message = nCode;
7169 msg.flags = hook|wparam|lparam;
7170 msg.wParam = wParam;
7171 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7172 add_message(&msg);
7174 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7176 /* WH_MOUSE_LL hook */
7177 if (nCode == HC_ACTION)
7179 struct message msg;
7180 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7182 /* we can't test for real mouse events */
7183 if (mhll->flags & LLMHF_INJECTED)
7185 msg.message = wParam;
7186 msg.flags = hook;
7187 add_message(&msg);
7189 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7192 /* Log also SetFocus(0) calls */
7193 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7195 if (GetClassNameA(hwnd, buf, sizeof(buf)))
7197 if (!lstrcmpiA(buf, "TestWindowClass") ||
7198 !lstrcmpiA(buf, "static"))
7200 struct message msg;
7202 msg.message = nCode;
7203 msg.flags = hook|wparam|lparam;
7204 msg.wParam = wParam;
7205 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7206 add_message(&msg);
7209 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7212 static DWORD WINAPI win_event_global_thread_proc(void *param)
7214 HWND hwnd;
7215 MSG msg;
7216 HANDLE hevent = *(HANDLE *)param;
7218 assert(pNotifyWinEvent);
7220 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7221 assert(hwnd);
7222 trace("created thread window %p\n", hwnd);
7224 *(HWND *)param = hwnd;
7226 flush_sequence();
7227 /* this event should be received only by our new hook proc,
7228 * an old one does not expect an event from another thread.
7230 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7231 SetEvent(hevent);
7233 while (GetMessage(&msg, 0, 0, 0))
7235 TranslateMessage(&msg);
7236 DispatchMessage(&msg);
7238 return 0;
7241 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7243 HWND hwnd;
7244 MSG msg;
7245 HANDLE hevent = *(HANDLE *)param;
7247 flush_sequence();
7248 /* these events should be received only by our new hook proc,
7249 * an old one does not expect an event from another thread.
7252 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7253 assert(hwnd);
7254 trace("created thread window %p\n", hwnd);
7256 *(HWND *)param = hwnd;
7258 /* Windows doesn't like when a thread plays games with the focus,
7259 that leads to all kinds of misbehaviours and failures to activate
7260 a window. So, better keep next lines commented out.
7261 SetFocus(0);
7262 SetFocus(hwnd);*/
7264 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7265 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7267 SetEvent(hevent);
7269 while (GetMessage(&msg, 0, 0, 0))
7271 TranslateMessage(&msg);
7272 DispatchMessage(&msg);
7274 return 0;
7277 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7279 HWND hwnd;
7280 MSG msg;
7281 HANDLE hevent = *(HANDLE *)param;
7283 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7284 assert(hwnd);
7285 trace("created thread window %p\n", hwnd);
7287 *(HWND *)param = hwnd;
7289 flush_sequence();
7291 /* Windows doesn't like when a thread plays games with the focus,
7292 * that leads to all kinds of misbehaviours and failures to activate
7293 * a window. So, better don't generate a mouse click message below.
7295 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7296 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7297 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7299 SetEvent(hevent);
7300 while (GetMessage(&msg, 0, 0, 0))
7302 TranslateMessage(&msg);
7303 DispatchMessage(&msg);
7305 return 0;
7308 static void test_winevents(void)
7310 BOOL ret;
7311 MSG msg;
7312 HWND hwnd, hwnd2;
7313 UINT i;
7314 HANDLE hthread, hevent;
7315 DWORD tid;
7316 HWINEVENTHOOK hhook;
7317 const struct message *events = WmWinEventsSeq;
7319 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7320 WS_OVERLAPPEDWINDOW,
7321 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7322 NULL, NULL, 0);
7323 assert(hwnd);
7325 /****** start of global hook test *************/
7326 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7327 if (!hCBT_global_hook)
7329 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7330 skip( "cannot set global hook\n" );
7331 return;
7334 hevent = CreateEventA(NULL, 0, 0, NULL);
7335 assert(hevent);
7336 hwnd2 = (HWND)hevent;
7338 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7339 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7341 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7343 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7345 flush_sequence();
7346 /* this one should be received only by old hook proc */
7347 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7348 /* this one should be received only by old hook proc */
7349 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7351 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7353 ret = UnhookWindowsHookEx(hCBT_global_hook);
7354 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7356 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7357 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7358 CloseHandle(hthread);
7359 CloseHandle(hevent);
7360 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7361 /****** end of global hook test *************/
7363 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7365 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7366 return;
7369 flush_sequence();
7371 if (0)
7373 /* this test doesn't pass under Win9x */
7374 /* win2k ignores events with hwnd == 0 */
7375 SetLastError(0xdeadbeef);
7376 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7377 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7378 GetLastError() == 0xdeadbeef, /* Win9x */
7379 "unexpected error %d\n", GetLastError());
7380 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7383 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7384 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7386 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7388 /****** start of event filtering test *************/
7389 hhook = (HWINEVENTHOOK)pSetWinEventHook(
7390 EVENT_OBJECT_SHOW, /* 0x8002 */
7391 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7392 GetModuleHandleA(0), win_event_global_hook_proc,
7393 GetCurrentProcessId(), 0,
7394 WINEVENT_INCONTEXT);
7395 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7397 hevent = CreateEventA(NULL, 0, 0, NULL);
7398 assert(hevent);
7399 hwnd2 = (HWND)hevent;
7401 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7402 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7404 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7406 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7408 flush_sequence();
7409 /* this one should be received only by old hook proc */
7410 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7411 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7412 /* this one should be received only by old hook proc */
7413 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7415 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7417 ret = pUnhookWinEvent(hhook);
7418 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7420 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7421 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7422 CloseHandle(hthread);
7423 CloseHandle(hevent);
7424 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7425 /****** end of event filtering test *************/
7427 /****** start of out of context event test *************/
7428 hhook = (HWINEVENTHOOK)pSetWinEventHook(
7429 EVENT_MIN, EVENT_MAX,
7430 0, win_event_global_hook_proc,
7431 GetCurrentProcessId(), 0,
7432 WINEVENT_OUTOFCONTEXT);
7433 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7435 hevent = CreateEventA(NULL, 0, 0, NULL);
7436 assert(hevent);
7437 hwnd2 = (HWND)hevent;
7439 flush_sequence();
7441 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7442 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7444 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7446 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7447 /* process pending winevent messages */
7448 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7449 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7451 flush_sequence();
7452 /* this one should be received only by old hook proc */
7453 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7454 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7455 /* this one should be received only by old hook proc */
7456 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7458 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7459 /* process pending winevent messages */
7460 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7461 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7463 ret = pUnhookWinEvent(hhook);
7464 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7466 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7467 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7468 CloseHandle(hthread);
7469 CloseHandle(hevent);
7470 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7471 /****** end of out of context event test *************/
7473 /****** start of MOUSE_LL hook test *************/
7474 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7475 /* WH_MOUSE_LL is not supported on Win9x platforms */
7476 if (!hCBT_global_hook)
7478 trace("Skipping WH_MOUSE_LL test on this platform\n");
7479 goto skip_mouse_ll_hook_test;
7482 hevent = CreateEventA(NULL, 0, 0, NULL);
7483 assert(hevent);
7484 hwnd2 = (HWND)hevent;
7486 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
7487 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7489 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
7490 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7492 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
7493 flush_sequence();
7495 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7496 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7497 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7499 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
7501 ret = UnhookWindowsHookEx(hCBT_global_hook);
7502 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7504 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7505 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7506 CloseHandle(hthread);
7507 CloseHandle(hevent);
7508 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7509 /****** end of MOUSE_LL hook test *************/
7510 skip_mouse_ll_hook_test:
7512 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7515 static void test_set_hook(void)
7517 BOOL ret;
7518 HHOOK hhook;
7519 HWINEVENTHOOK hwinevent_hook;
7521 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
7522 ok(hhook != 0, "local hook does not require hModule set to 0\n");
7523 UnhookWindowsHookEx(hhook);
7525 if (0)
7527 /* this test doesn't pass under Win9x: BUG! */
7528 SetLastError(0xdeadbeef);
7529 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
7530 ok(!hhook, "global hook requires hModule != 0\n");
7531 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
7534 SetLastError(0xdeadbeef);
7535 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
7536 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
7537 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
7538 GetLastError() == 0xdeadbeef, /* Win9x */
7539 "unexpected error %d\n", GetLastError());
7541 SetLastError(0xdeadbeef);
7542 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
7543 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
7544 GetLastError() == 0xdeadbeef, /* Win9x */
7545 "unexpected error %d\n", GetLastError());
7547 if (!pSetWinEventHook || !pUnhookWinEvent) return;
7549 /* even process local incontext hooks require hmodule */
7550 SetLastError(0xdeadbeef);
7551 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7552 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
7553 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7554 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7555 GetLastError() == 0xdeadbeef, /* Win9x */
7556 "unexpected error %d\n", GetLastError());
7558 /* even thread local incontext hooks require hmodule */
7559 SetLastError(0xdeadbeef);
7560 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7561 0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
7562 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7563 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7564 GetLastError() == 0xdeadbeef, /* Win9x */
7565 "unexpected error %d\n", GetLastError());
7567 if (0)
7569 /* these 3 tests don't pass under Win9x */
7570 SetLastError(0xdeadbeef);
7571 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
7572 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7573 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7574 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7576 SetLastError(0xdeadbeef);
7577 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
7578 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7579 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7580 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7582 SetLastError(0xdeadbeef);
7583 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7584 0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
7585 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
7586 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
7589 SetLastError(0xdeadbeef);
7590 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
7591 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7592 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7593 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7594 ret = pUnhookWinEvent(hwinevent_hook);
7595 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7597 todo_wine {
7598 /* This call succeeds under win2k SP4, but fails under Wine.
7599 Does win2k test/use passed process id? */
7600 SetLastError(0xdeadbeef);
7601 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7602 0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
7603 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7604 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7605 ret = pUnhookWinEvent(hwinevent_hook);
7606 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7609 SetLastError(0xdeadbeef);
7610 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
7611 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7612 GetLastError() == 0xdeadbeef, /* Win9x */
7613 "unexpected error %d\n", GetLastError());
7616 static const struct message ScrollWindowPaint1[] = {
7617 { WM_PAINT, sent },
7618 { WM_ERASEBKGND, sent|beginpaint },
7619 { 0 }
7622 static const struct message ScrollWindowPaint2[] = {
7623 { WM_PAINT, sent },
7624 { 0 }
7627 static void test_scrollwindowex(void)
7629 HWND hwnd, hchild;
7630 RECT rect={0,0,130,130};
7632 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
7633 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
7634 100, 100, 200, 200, 0, 0, 0, NULL);
7635 ok (hwnd != 0, "Failed to create overlapped window\n");
7636 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
7637 WS_VISIBLE|WS_CAPTION|WS_CHILD,
7638 10, 10, 150, 150, hwnd, 0, 0, NULL);
7639 ok (hchild != 0, "Failed to create child\n");
7640 UpdateWindow(hwnd);
7641 flush_events();
7642 flush_sequence();
7644 /* scroll without the child window */
7645 trace("start scroll\n");
7646 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7647 SW_ERASE|SW_INVALIDATE);
7648 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7649 trace("end scroll\n");
7650 flush_sequence();
7651 flush_events();
7652 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7653 flush_events();
7654 flush_sequence();
7656 /* Now without the SW_ERASE flag */
7657 trace("start scroll\n");
7658 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
7659 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7660 trace("end scroll\n");
7661 flush_sequence();
7662 flush_events();
7663 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
7664 flush_events();
7665 flush_sequence();
7667 /* now scroll the child window as well */
7668 trace("start scroll\n");
7669 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7670 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
7671 todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
7672 /* windows sometimes a WM_MOVE */
7673 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7675 trace("end scroll\n");
7676 flush_sequence();
7677 flush_events();
7678 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7679 flush_events();
7680 flush_sequence();
7682 /* now scroll with ScrollWindow() */
7683 trace("start scroll with ScrollWindow\n");
7684 ScrollWindow( hwnd, 5, 5, NULL, NULL);
7685 trace("end scroll\n");
7686 flush_sequence();
7687 flush_events();
7688 ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
7690 ok(DestroyWindow(hchild), "failed to destroy window\n");
7691 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7692 flush_sequence();
7695 static const struct message destroy_window_with_children[] = {
7696 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7697 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
7698 { 0x0090, sent|optional },
7699 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
7700 { 0x0090, sent|optional },
7701 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7702 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7703 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7704 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7705 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
7706 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7707 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7708 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7709 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7710 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7711 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7712 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7713 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7714 { 0 }
7717 static void test_DestroyWindow(void)
7719 BOOL ret;
7720 HWND parent, child1, child2, child3, child4, test;
7721 UINT child_id = WND_CHILD_ID + 1;
7723 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7724 100, 100, 200, 200, 0, 0, 0, NULL);
7725 assert(parent != 0);
7726 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7727 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
7728 assert(child1 != 0);
7729 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7730 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
7731 assert(child2 != 0);
7732 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7733 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
7734 assert(child3 != 0);
7735 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
7736 0, 0, 50, 50, parent, 0, 0, NULL);
7737 assert(child4 != 0);
7739 /* test owner/parent of child2 */
7740 test = GetParent(child2);
7741 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7742 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7743 if(pGetAncestor) {
7744 test = pGetAncestor(child2, GA_PARENT);
7745 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7747 test = GetWindow(child2, GW_OWNER);
7748 ok(!test, "wrong owner %p\n", test);
7750 test = SetParent(child2, parent);
7751 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
7753 /* test owner/parent of the parent */
7754 test = GetParent(parent);
7755 ok(!test, "wrong parent %p\n", test);
7756 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
7757 if(pGetAncestor) {
7758 test = pGetAncestor(parent, GA_PARENT);
7759 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7761 test = GetWindow(parent, GW_OWNER);
7762 ok(!test, "wrong owner %p\n", test);
7764 /* test owner/parent of child1 */
7765 test = GetParent(child1);
7766 ok(test == parent, "wrong parent %p\n", test);
7767 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
7768 if(pGetAncestor) {
7769 test = pGetAncestor(child1, GA_PARENT);
7770 ok(test == parent, "wrong parent %p\n", test);
7772 test = GetWindow(child1, GW_OWNER);
7773 ok(!test, "wrong owner %p\n", test);
7775 /* test owner/parent of child2 */
7776 test = GetParent(child2);
7777 ok(test == parent, "wrong parent %p\n", test);
7778 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7779 if(pGetAncestor) {
7780 test = pGetAncestor(child2, GA_PARENT);
7781 ok(test == parent, "wrong parent %p\n", test);
7783 test = GetWindow(child2, GW_OWNER);
7784 ok(!test, "wrong owner %p\n", test);
7786 /* test owner/parent of child3 */
7787 test = GetParent(child3);
7788 ok(test == child1, "wrong parent %p\n", test);
7789 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
7790 if(pGetAncestor) {
7791 test = pGetAncestor(child3, GA_PARENT);
7792 ok(test == child1, "wrong parent %p\n", test);
7794 test = GetWindow(child3, GW_OWNER);
7795 ok(!test, "wrong owner %p\n", test);
7797 /* test owner/parent of child4 */
7798 test = GetParent(child4);
7799 ok(test == parent, "wrong parent %p\n", test);
7800 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
7801 if(pGetAncestor) {
7802 test = pGetAncestor(child4, GA_PARENT);
7803 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7805 test = GetWindow(child4, GW_OWNER);
7806 ok(test == parent, "wrong owner %p\n", test);
7808 flush_sequence();
7810 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
7811 parent, child1, child2, child3, child4);
7813 SetCapture(child4);
7814 test = GetCapture();
7815 ok(test == child4, "wrong capture window %p\n", test);
7817 test_DestroyWindow_flag = TRUE;
7818 ret = DestroyWindow(parent);
7819 ok( ret, "DestroyWindow() error %d\n", GetLastError());
7820 test_DestroyWindow_flag = FALSE;
7821 ok_sequence(destroy_window_with_children, "destroy window with children", 0);
7823 ok(!IsWindow(parent), "parent still exists\n");
7824 ok(!IsWindow(child1), "child1 still exists\n");
7825 ok(!IsWindow(child2), "child2 still exists\n");
7826 ok(!IsWindow(child3), "child3 still exists\n");
7827 ok(!IsWindow(child4), "child4 still exists\n");
7829 test = GetCapture();
7830 ok(!test, "wrong capture window %p\n", test);
7834 static const struct message WmDispatchPaint[] = {
7835 { WM_NCPAINT, sent },
7836 { WM_GETTEXT, sent|defwinproc|optional },
7837 { WM_GETTEXT, sent|defwinproc|optional },
7838 { WM_ERASEBKGND, sent },
7839 { 0 }
7842 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7844 if (message == WM_PAINT) return 0;
7845 return MsgCheckProcA( hwnd, message, wParam, lParam );
7848 static void test_DispatchMessage(void)
7850 RECT rect;
7851 MSG msg;
7852 int count;
7853 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7854 100, 100, 200, 200, 0, 0, 0, NULL);
7855 ShowWindow( hwnd, SW_SHOW );
7856 UpdateWindow( hwnd );
7857 flush_events();
7858 flush_sequence();
7859 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
7861 SetRect( &rect, -5, -5, 5, 5 );
7862 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7863 count = 0;
7864 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7866 if (msg.message != WM_PAINT) DispatchMessage( &msg );
7867 else
7869 flush_sequence();
7870 DispatchMessage( &msg );
7871 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
7872 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7873 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
7874 if (++count > 10) break;
7877 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
7879 trace("now without DispatchMessage\n");
7880 flush_sequence();
7881 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7882 count = 0;
7883 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7885 if (msg.message != WM_PAINT) DispatchMessage( &msg );
7886 else
7888 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7889 flush_sequence();
7890 /* this will send WM_NCCPAINT just like DispatchMessage does */
7891 GetUpdateRgn( hwnd, hrgn, TRUE );
7892 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7893 DeleteObject( hrgn );
7894 GetClientRect( hwnd, &rect );
7895 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
7896 ok( !count, "Got multiple WM_PAINTs\n" );
7897 if (++count > 10) break;
7900 DestroyWindow(hwnd);
7904 static const struct message WmUser[] = {
7905 { WM_USER, sent },
7906 { 0 }
7909 struct sendmsg_info
7911 HWND hwnd;
7912 DWORD timeout;
7913 DWORD ret;
7916 static DWORD CALLBACK send_msg_thread( LPVOID arg )
7918 struct sendmsg_info *info = arg;
7919 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
7920 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
7921 return 0;
7924 static void wait_for_thread( HANDLE thread )
7926 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
7928 MSG msg;
7929 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
7933 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7935 if (message == WM_USER) Sleep(200);
7936 return MsgCheckProcA( hwnd, message, wParam, lParam );
7939 static void test_SendMessageTimeout(void)
7941 HANDLE thread;
7942 struct sendmsg_info info;
7943 DWORD tid;
7945 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7946 100, 100, 200, 200, 0, 0, 0, NULL);
7947 flush_events();
7948 flush_sequence();
7950 info.timeout = 1000;
7951 info.ret = 0xdeadbeef;
7952 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7953 wait_for_thread( thread );
7954 CloseHandle( thread );
7955 ok( info.ret == 1, "SendMessageTimeout failed\n" );
7956 ok_sequence( WmUser, "WmUser", FALSE );
7958 info.timeout = 1;
7959 info.ret = 0xdeadbeef;
7960 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7961 Sleep(100); /* SendMessageTimeout should time out here */
7962 wait_for_thread( thread );
7963 CloseHandle( thread );
7964 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7965 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7967 /* 0 means infinite timeout */
7968 info.timeout = 0;
7969 info.ret = 0xdeadbeef;
7970 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7971 Sleep(100);
7972 wait_for_thread( thread );
7973 CloseHandle( thread );
7974 ok( info.ret == 1, "SendMessageTimeout failed\n" );
7975 ok_sequence( WmUser, "WmUser", FALSE );
7977 /* timeout is treated as signed despite the prototype */
7978 info.timeout = 0x7fffffff;
7979 info.ret = 0xdeadbeef;
7980 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7981 Sleep(100);
7982 wait_for_thread( thread );
7983 CloseHandle( thread );
7984 ok( info.ret == 1, "SendMessageTimeout failed\n" );
7985 ok_sequence( WmUser, "WmUser", FALSE );
7987 info.timeout = 0x80000000;
7988 info.ret = 0xdeadbeef;
7989 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7990 Sleep(100);
7991 wait_for_thread( thread );
7992 CloseHandle( thread );
7993 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7994 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7996 /* now check for timeout during message processing */
7997 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
7998 info.timeout = 100;
7999 info.ret = 0xdeadbeef;
8000 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8001 wait_for_thread( thread );
8002 CloseHandle( thread );
8003 /* we should time out but still get the message */
8004 ok( info.ret == 0, "SendMessageTimeout failed\n" );
8005 ok_sequence( WmUser, "WmUser", FALSE );
8007 DestroyWindow( info.hwnd );
8011 /****************** edit message test *************************/
8012 #define ID_EDIT 0x1234
8013 static const struct message sl_edit_setfocus[] =
8015 { HCBT_SETFOCUS, hook },
8016 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8017 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8018 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8019 { WM_SETFOCUS, sent|wparam, 0 },
8020 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8021 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8022 { WM_CTLCOLOREDIT, sent|parent },
8023 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8024 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8025 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8026 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8027 { 0 }
8029 static const struct message ml_edit_setfocus[] =
8031 { HCBT_SETFOCUS, hook },
8032 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8033 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8034 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8035 { WM_SETFOCUS, sent|wparam, 0 },
8036 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8037 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8038 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8039 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8040 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8041 { 0 }
8043 static const struct message sl_edit_killfocus[] =
8045 { HCBT_SETFOCUS, hook },
8046 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8047 { WM_KILLFOCUS, sent|wparam, 0 },
8048 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8049 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8050 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8051 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8052 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8053 { 0 }
8055 static const struct message sl_edit_lbutton_dblclk[] =
8057 { WM_LBUTTONDBLCLK, sent },
8058 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8059 { 0 }
8061 static const struct message sl_edit_lbutton_down[] =
8063 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8064 { HCBT_SETFOCUS, hook },
8065 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8066 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8067 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8068 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8069 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8070 { WM_CTLCOLOREDIT, sent|parent },
8071 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8072 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8073 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8074 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8075 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8076 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8077 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8078 { WM_CTLCOLOREDIT, sent|parent|optional },
8079 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8080 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8081 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8082 { 0 }
8084 static const struct message ml_edit_lbutton_down[] =
8086 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8087 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8088 { HCBT_SETFOCUS, hook },
8089 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8090 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8091 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8092 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8093 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8094 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8095 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8096 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8097 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8098 { 0 }
8100 static const struct message sl_edit_lbutton_up[] =
8102 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8103 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8104 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8105 { WM_CAPTURECHANGED, sent|defwinproc },
8106 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8107 { 0 }
8109 static const struct message ml_edit_lbutton_up[] =
8111 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8112 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8113 { WM_CAPTURECHANGED, sent|defwinproc },
8114 { 0 }
8117 static WNDPROC old_edit_proc;
8119 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8121 static long defwndproc_counter = 0;
8122 LRESULT ret;
8123 struct message msg;
8125 trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
8127 /* explicitly ignore WM_GETICON message */
8128 if (message == WM_GETICON) return 0;
8130 msg.message = message;
8131 msg.flags = sent|wparam|lparam;
8132 if (defwndproc_counter) msg.flags |= defwinproc;
8133 msg.wParam = wParam;
8134 msg.lParam = lParam;
8135 add_message(&msg);
8137 defwndproc_counter++;
8138 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8139 defwndproc_counter--;
8141 return ret;
8144 static void subclass_edit(void)
8146 WNDCLASSA cls;
8148 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8150 old_edit_proc = cls.lpfnWndProc;
8152 cls.hInstance = GetModuleHandle(0);
8153 cls.lpfnWndProc = edit_hook_proc;
8154 cls.lpszClassName = "my_edit_class";
8155 UnregisterClass(cls.lpszClassName, cls.hInstance);
8156 if (!RegisterClassA(&cls)) assert(0);
8159 static void test_edit_messages(void)
8161 HWND hwnd, parent;
8162 DWORD dlg_code;
8164 subclass_edit();
8165 log_all_parent_messages++;
8167 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8168 100, 100, 200, 200, 0, 0, 0, NULL);
8169 ok (parent != 0, "Failed to create parent window\n");
8171 /* test single line edit */
8172 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8173 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8174 ok(hwnd != 0, "Failed to create edit window\n");
8176 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8177 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8179 ShowWindow(hwnd, SW_SHOW);
8180 UpdateWindow(hwnd);
8181 SetFocus(0);
8182 flush_sequence();
8184 SetFocus(hwnd);
8185 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8187 SetFocus(0);
8188 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8190 SetFocus(0);
8191 ReleaseCapture();
8192 flush_sequence();
8194 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8195 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8197 SetFocus(0);
8198 ReleaseCapture();
8199 flush_sequence();
8201 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8202 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8204 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8205 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8207 DestroyWindow(hwnd);
8209 /* test multiline edit */
8210 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8211 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8212 ok(hwnd != 0, "Failed to create edit window\n");
8214 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8215 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8216 "wrong dlg_code %08x\n", dlg_code);
8218 ShowWindow(hwnd, SW_SHOW);
8219 UpdateWindow(hwnd);
8220 SetFocus(0);
8221 flush_sequence();
8223 SetFocus(hwnd);
8224 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8226 SetFocus(0);
8227 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8229 SetFocus(0);
8230 ReleaseCapture();
8231 flush_sequence();
8233 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8234 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8236 SetFocus(0);
8237 ReleaseCapture();
8238 flush_sequence();
8240 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8241 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8243 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8244 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8246 DestroyWindow(hwnd);
8247 DestroyWindow(parent);
8249 log_all_parent_messages--;
8252 /**************************** End of Edit test ******************************/
8254 static const struct message WmKeyDownSkippedSeq[] =
8256 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8257 { 0 }
8259 static const struct message WmKeyUpSkippedSeq[] =
8261 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8262 { 0 }
8265 #define EV_START_STOP 0
8266 #define EV_SENDMSG 1
8267 #define EV_ACK 2
8269 struct peekmsg_info
8271 HWND hwnd;
8272 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8275 static DWORD CALLBACK send_msg_thread_2(void *param)
8277 DWORD ret;
8278 struct peekmsg_info *info = param;
8280 trace("thread: waiting for start\n");
8281 WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
8282 trace("thread: looping\n");
8284 while (1)
8286 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8288 switch (ret)
8290 case WAIT_OBJECT_0 + EV_START_STOP:
8291 trace("thread: exiting\n");
8292 return 0;
8294 case WAIT_OBJECT_0 + EV_SENDMSG:
8295 trace("thread: sending message\n");
8296 SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
8297 SetEvent(info->hevent[EV_ACK]);
8298 break;
8300 default:
8301 trace("unexpected return: %04x\n", ret);
8302 assert(0);
8303 break;
8306 return 0;
8309 static void test_PeekMessage(void)
8311 MSG msg;
8312 HANDLE hthread;
8313 DWORD tid, qstatus;
8314 UINT qs_all_input = QS_ALLINPUT;
8315 UINT qs_input = QS_INPUT;
8316 BOOL ret;
8317 struct peekmsg_info info;
8319 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8320 100, 100, 200, 200, 0, 0, 0, NULL);
8321 assert(info.hwnd);
8322 ShowWindow(info.hwnd, SW_SHOW);
8323 UpdateWindow(info.hwnd);
8324 SetFocus(info.hwnd);
8326 info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
8327 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8328 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8330 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8331 Sleep(100);
8333 trace("signalling to start looping\n");
8334 SetEvent(info.hevent[EV_START_STOP]);
8336 flush_events();
8337 flush_sequence();
8339 SetLastError(0xdeadbeef);
8340 qstatus = GetQueueStatus(qs_all_input);
8341 if (GetLastError() == ERROR_INVALID_FLAGS)
8343 trace("QS_RAWINPUT not supported on this platform\n");
8344 qs_all_input &= ~QS_RAWINPUT;
8345 qs_input &= ~QS_RAWINPUT;
8347 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8349 trace("signalling to send message\n");
8350 SetEvent(info.hevent[EV_SENDMSG]);
8351 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8353 /* pass invalid QS_xxxx flags */
8354 SetLastError(0xdeadbeef);
8355 qstatus = GetQueueStatus(0xffffffff);
8356 ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
8357 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8359 qstatus = GetQueueStatus(qs_all_input);
8360 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8361 "wrong qstatus %08x\n", qstatus);
8363 msg.message = 0;
8364 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8365 ok(!ret,
8366 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8367 msg.message);
8368 ok_sequence(WmUser, "WmUser", FALSE);
8370 qstatus = GetQueueStatus(qs_all_input);
8371 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8373 keybd_event('N', 0, 0, 0);
8374 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8375 qstatus = GetQueueStatus(qs_all_input);
8376 ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8377 "wrong qstatus %08x\n", qstatus);
8379 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8380 qstatus = GetQueueStatus(qs_all_input);
8381 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8382 "wrong qstatus %08x\n", qstatus);
8384 InvalidateRect(info.hwnd, NULL, FALSE);
8385 qstatus = GetQueueStatus(qs_all_input);
8386 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8387 "wrong qstatus %08x\n", qstatus);
8389 trace("signalling to send message\n");
8390 SetEvent(info.hevent[EV_SENDMSG]);
8391 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8393 qstatus = GetQueueStatus(qs_all_input);
8394 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8395 "wrong qstatus %08x\n", qstatus);
8397 msg.message = 0;
8398 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8399 ok(!ret,
8400 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8401 msg.message);
8402 ok_sequence(WmUser, "WmUser", FALSE);
8404 qstatus = GetQueueStatus(qs_all_input);
8405 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8406 "wrong qstatus %08x\n", qstatus);
8408 trace("signalling to send message\n");
8409 SetEvent(info.hevent[EV_SENDMSG]);
8410 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8412 qstatus = GetQueueStatus(qs_all_input);
8413 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8414 "wrong qstatus %08x\n", qstatus);
8416 msg.message = 0;
8417 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8418 ok(!ret,
8419 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8420 msg.message);
8421 ok_sequence(WmUser, "WmUser", FALSE);
8423 qstatus = GetQueueStatus(qs_all_input);
8424 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8425 "wrong qstatus %08x\n", qstatus);
8427 msg.message = 0;
8428 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8429 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8430 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8431 ret, msg.message, msg.wParam);
8432 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8434 qstatus = GetQueueStatus(qs_all_input);
8435 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8436 "wrong qstatus %08x\n", qstatus);
8438 msg.message = 0;
8439 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8440 ok(!ret,
8441 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8442 msg.message);
8443 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8445 qstatus = GetQueueStatus(qs_all_input);
8446 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8447 "wrong qstatus %08x\n", qstatus);
8449 msg.message = 0;
8450 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8451 ok(ret && msg.message == WM_PAINT,
8452 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8453 DispatchMessageA(&msg);
8454 ok_sequence(WmPaint, "WmPaint", FALSE);
8456 qstatus = GetQueueStatus(qs_all_input);
8457 ok(qstatus == MAKELONG(0, QS_KEY),
8458 "wrong qstatus %08x\n", qstatus);
8460 msg.message = 0;
8461 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8462 ok(!ret,
8463 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8464 msg.message);
8465 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8467 qstatus = GetQueueStatus(qs_all_input);
8468 ok(qstatus == MAKELONG(0, QS_KEY),
8469 "wrong qstatus %08x\n", qstatus);
8471 trace("signalling to send message\n");
8472 SetEvent(info.hevent[EV_SENDMSG]);
8473 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8475 qstatus = GetQueueStatus(qs_all_input);
8476 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8477 "wrong qstatus %08x\n", qstatus);
8479 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8481 qstatus = GetQueueStatus(qs_all_input);
8482 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8483 "wrong qstatus %08x\n", qstatus);
8485 msg.message = 0;
8486 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8487 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8488 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8489 ret, msg.message, msg.wParam);
8490 ok_sequence(WmUser, "WmUser", FALSE);
8492 qstatus = GetQueueStatus(qs_all_input);
8493 ok(qstatus == MAKELONG(0, QS_KEY),
8494 "wrong qstatus %08x\n", qstatus);
8496 msg.message = 0;
8497 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8498 ok(!ret,
8499 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8500 msg.message);
8501 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8503 qstatus = GetQueueStatus(qs_all_input);
8504 ok(qstatus == MAKELONG(0, QS_KEY),
8505 "wrong qstatus %08x\n", qstatus);
8507 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8509 qstatus = GetQueueStatus(qs_all_input);
8510 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8511 "wrong qstatus %08x\n", qstatus);
8513 trace("signalling to send message\n");
8514 SetEvent(info.hevent[EV_SENDMSG]);
8515 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8517 qstatus = GetQueueStatus(qs_all_input);
8518 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8519 "wrong qstatus %08x\n", qstatus);
8521 msg.message = 0;
8522 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
8523 ok(!ret,
8524 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8525 msg.message);
8526 ok_sequence(WmUser, "WmUser", FALSE);
8528 qstatus = GetQueueStatus(qs_all_input);
8529 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8530 "wrong qstatus %08x\n", qstatus);
8532 msg.message = 0;
8533 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8534 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8535 else /* workaround for a missing QS_RAWINPUT support */
8536 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
8537 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
8538 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
8539 ret, msg.message, msg.wParam);
8540 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
8542 qstatus = GetQueueStatus(qs_all_input);
8543 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8544 "wrong qstatus %08x\n", qstatus);
8546 msg.message = 0;
8547 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8548 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8549 else /* workaround for a missing QS_RAWINPUT support */
8550 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
8551 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
8552 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
8553 ret, msg.message, msg.wParam);
8554 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
8556 qstatus = GetQueueStatus(qs_all_input);
8557 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8558 "wrong qstatus %08x\n", qstatus);
8560 msg.message = 0;
8561 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
8562 ok(!ret,
8563 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8564 msg.message);
8565 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8567 qstatus = GetQueueStatus(qs_all_input);
8568 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8569 "wrong qstatus %08x\n", qstatus);
8571 msg.message = 0;
8572 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8573 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8574 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8575 ret, msg.message, msg.wParam);
8576 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8578 qstatus = GetQueueStatus(qs_all_input);
8579 ok(qstatus == 0,
8580 "wrong qstatus %08x\n", qstatus);
8582 msg.message = 0;
8583 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8584 ok(!ret,
8585 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8586 msg.message);
8587 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8589 qstatus = GetQueueStatus(qs_all_input);
8590 ok(qstatus == 0,
8591 "wrong qstatus %08x\n", qstatus);
8593 /* test whether presence of the quit flag in the queue affects
8594 * the queue state
8596 PostQuitMessage(0x1234abcd);
8598 qstatus = GetQueueStatus(qs_all_input);
8599 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8600 "wrong qstatus %08x\n", qstatus);
8602 PostMessageA(info.hwnd, WM_USER, 0, 0);
8604 qstatus = GetQueueStatus(qs_all_input);
8605 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8606 "wrong qstatus %08x\n", qstatus);
8608 msg.message = 0;
8609 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8610 ok(ret && msg.message == WM_USER,
8611 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
8612 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8614 qstatus = GetQueueStatus(qs_all_input);
8615 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8616 "wrong qstatus %08x\n", qstatus);
8618 msg.message = 0;
8619 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8620 ok(ret && msg.message == WM_QUIT,
8621 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
8622 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
8623 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
8624 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8626 qstatus = GetQueueStatus(qs_all_input);
8627 todo_wine {
8628 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8629 "wrong qstatus %08x\n", qstatus);
8632 msg.message = 0;
8633 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8634 ok(!ret,
8635 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8636 msg.message);
8637 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8639 qstatus = GetQueueStatus(qs_all_input);
8640 ok(qstatus == 0,
8641 "wrong qstatus %08x\n", qstatus);
8643 trace("signalling to exit\n");
8644 SetEvent(info.hevent[EV_START_STOP]);
8646 WaitForSingleObject(hthread, INFINITE);
8648 CloseHandle(hthread);
8649 CloseHandle(info.hevent[0]);
8650 CloseHandle(info.hevent[1]);
8651 CloseHandle(info.hevent[2]);
8653 DestroyWindow(info.hwnd);
8656 static void wait_move_event(HWND hwnd, int x, int y)
8658 MSG msg;
8659 DWORD time;
8660 BOOL ret;
8661 int go = 0;
8663 time = GetTickCount();
8664 while (GetTickCount() - time < 200 && !go) {
8665 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8666 go = ret && msg.pt.x > x && msg.pt.y > y;
8670 #define STEP 20
8671 static void test_PeekMessage2(void)
8673 HWND hwnd;
8674 BOOL ret;
8675 MSG msg;
8676 UINT message;
8677 DWORD time1, time2, time3;
8678 int x1, y1, x2, y2, x3, y3;
8679 POINT pos;
8681 time1 = time2 = time3 = 0;
8682 x1 = y1 = x2 = y2 = x3 = y3 = 0;
8684 /* Initialise window and make sure it is ready for events */
8685 hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
8686 10, 10, 800, 800, NULL, NULL, NULL, NULL);
8687 assert(hwnd);
8688 trace("Window for test_PeekMessage2 %p\n", hwnd);
8689 ShowWindow(hwnd, SW_SHOW);
8690 UpdateWindow(hwnd);
8691 SetFocus(hwnd);
8692 GetCursorPos(&pos);
8693 SetCursorPos(100, 100);
8694 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
8695 flush_events();
8697 /* Do initial mousemove, wait until we can see it
8698 and then do our test peek with PM_NOREMOVE. */
8699 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8700 wait_move_event(hwnd, 80, 80);
8702 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8703 ok(ret, "no message available\n");
8704 if (ret) {
8705 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8706 message = msg.message;
8707 time1 = msg.time;
8708 x1 = msg.pt.x;
8709 y1 = msg.pt.y;
8710 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8713 /* Allow time to advance a bit, and then simulate the user moving their
8714 * mouse around. After that we peek again with PM_NOREMOVE.
8715 * Although the previous mousemove message was never removed, the
8716 * mousemove we now peek should reflect the recent mouse movements
8717 * because the input queue will merge the move events. */
8718 Sleep(2);
8719 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8720 wait_move_event(hwnd, x1, y1);
8722 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8723 ok(ret, "no message available\n");
8724 if (ret) {
8725 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8726 message = msg.message;
8727 time2 = msg.time;
8728 x2 = msg.pt.x;
8729 y2 = msg.pt.y;
8730 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8731 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
8732 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
8735 /* Have another go, to drive the point home */
8736 Sleep(2);
8737 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8738 wait_move_event(hwnd, x2, y2);
8740 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8741 ok(ret, "no message available\n");
8742 if (ret) {
8743 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8744 message = msg.message;
8745 time3 = msg.time;
8746 x3 = msg.pt.x;
8747 y3 = msg.pt.y;
8748 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8749 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
8750 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
8753 DestroyWindow(hwnd);
8754 SetCursorPos(pos.x, pos.y);
8755 flush_events();
8758 static void test_quit_message(void)
8760 MSG msg;
8761 BOOL ret;
8763 /* test using PostQuitMessage */
8764 PostQuitMessage(0xbeef);
8766 ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8767 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8768 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8769 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
8771 ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8772 ok(ret, "PostMessage failed with error %d\n", GetLastError());
8774 ret = GetMessage(&msg, NULL, 0, 0);
8775 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8776 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8778 /* note: WM_QUIT message received after WM_USER message */
8779 ret = GetMessage(&msg, NULL, 0, 0);
8780 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8781 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8782 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
8784 ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
8785 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
8787 /* now test with PostThreadMessage - different behaviour! */
8788 PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
8790 ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8791 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8792 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8793 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
8795 ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8796 ok(ret, "PostMessage failed with error %d\n", GetLastError());
8798 /* note: we receive the WM_QUIT message first this time */
8799 ret = GetMessage(&msg, NULL, 0, 0);
8800 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8801 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8802 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
8804 ret = GetMessage(&msg, NULL, 0, 0);
8805 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8806 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8809 static const struct message WmMouseHoverSeq[] = {
8810 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
8811 { WM_MOUSEACTIVATE, sent|optional },
8812 { WM_TIMER, sent|optional }, /* XP sends it */
8813 { WM_SYSTIMER, sent },
8814 { WM_MOUSEHOVER, sent|wparam, 0 },
8815 { 0 }
8818 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
8820 MSG msg;
8821 DWORD start_ticks, end_ticks;
8823 start_ticks = GetTickCount();
8824 /* add some deviation (5%) to cover not expected delays */
8825 start_ticks += timeout / 20;
8829 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
8831 /* Timer proc messages are not dispatched to the window proc,
8832 * and therefore not logged.
8834 if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
8836 struct message s_msg;
8838 s_msg.message = msg.message;
8839 s_msg.flags = sent|wparam|lparam;
8840 s_msg.wParam = msg.wParam;
8841 s_msg.lParam = msg.lParam;
8842 add_message(&s_msg);
8844 DispatchMessage(&msg);
8847 end_ticks = GetTickCount();
8849 /* inject WM_MOUSEMOVE to see how it changes tracking */
8850 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
8852 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8853 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8855 inject_mouse_move = FALSE;
8857 } while (start_ticks + timeout >= end_ticks);
8860 static void test_TrackMouseEvent(void)
8862 TRACKMOUSEEVENT tme;
8863 BOOL ret;
8864 HWND hwnd, hchild;
8865 RECT rc_parent, rc_child;
8866 UINT default_hover_time, hover_width = 0, hover_height = 0;
8868 #define track_hover(track_hwnd, track_hover_time) \
8869 tme.cbSize = sizeof(tme); \
8870 tme.dwFlags = TME_HOVER; \
8871 tme.hwndTrack = track_hwnd; \
8872 tme.dwHoverTime = track_hover_time; \
8873 SetLastError(0xdeadbeef); \
8874 ret = pTrackMouseEvent(&tme); \
8875 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
8877 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
8878 tme.cbSize = sizeof(tme); \
8879 tme.dwFlags = TME_QUERY; \
8880 tme.hwndTrack = (HWND)0xdeadbeef; \
8881 tme.dwHoverTime = 0xdeadbeef; \
8882 SetLastError(0xdeadbeef); \
8883 ret = pTrackMouseEvent(&tme); \
8884 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
8885 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
8886 ok(tme.dwFlags == (expected_track_flags), \
8887 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
8888 ok(tme.hwndTrack == (expected_track_hwnd), \
8889 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
8890 ok(tme.dwHoverTime == (expected_hover_time), \
8891 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
8893 #define track_hover_cancel(track_hwnd) \
8894 tme.cbSize = sizeof(tme); \
8895 tme.dwFlags = TME_HOVER | TME_CANCEL; \
8896 tme.hwndTrack = track_hwnd; \
8897 tme.dwHoverTime = 0xdeadbeef; \
8898 SetLastError(0xdeadbeef); \
8899 ret = pTrackMouseEvent(&tme); \
8900 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
8902 default_hover_time = 0xdeadbeef;
8903 SetLastError(0xdeadbeef);
8904 ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
8905 ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
8906 if (!ret) default_hover_time = 400;
8907 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
8909 SetLastError(0xdeadbeef);
8910 ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
8911 ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
8912 if (!ret) hover_width = 4;
8913 SetLastError(0xdeadbeef);
8914 ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
8915 ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
8916 if (!ret) hover_height = 4;
8917 trace("hover rect is %u x %d\n", hover_width, hover_height);
8919 hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
8920 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8921 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8922 NULL, NULL, 0);
8923 assert(hwnd);
8925 hchild = CreateWindowEx(0, "TestWindowClass", NULL,
8926 WS_CHILD | WS_BORDER | WS_VISIBLE,
8927 50, 50, 200, 200, hwnd,
8928 NULL, NULL, 0);
8929 assert(hchild);
8931 flush_events();
8932 flush_sequence();
8934 tme.cbSize = 0;
8935 tme.dwFlags = TME_QUERY;
8936 tme.hwndTrack = (HWND)0xdeadbeef;
8937 tme.dwHoverTime = 0xdeadbeef;
8938 SetLastError(0xdeadbeef);
8939 ret = pTrackMouseEvent(&tme);
8940 ok(!ret, "TrackMouseEvent should fail\n");
8941 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
8943 tme.cbSize = sizeof(tme);
8944 tme.dwFlags = TME_HOVER;
8945 tme.hwndTrack = (HWND)0xdeadbeef;
8946 tme.dwHoverTime = 0xdeadbeef;
8947 SetLastError(0xdeadbeef);
8948 ret = pTrackMouseEvent(&tme);
8949 ok(!ret, "TrackMouseEvent should fail\n");
8950 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8952 tme.cbSize = sizeof(tme);
8953 tme.dwFlags = TME_HOVER | TME_CANCEL;
8954 tme.hwndTrack = (HWND)0xdeadbeef;
8955 tme.dwHoverTime = 0xdeadbeef;
8956 SetLastError(0xdeadbeef);
8957 ret = pTrackMouseEvent(&tme);
8958 ok(!ret, "TrackMouseEvent should fail\n");
8959 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8961 GetWindowRect(hwnd, &rc_parent);
8962 GetWindowRect(hchild, &rc_child);
8963 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
8965 /* Process messages so that the system updates its internal current
8966 * window and hittest, otherwise TrackMouseEvent calls don't have any
8967 * effect.
8969 flush_events();
8970 flush_sequence();
8972 track_query(0, NULL, 0);
8973 track_hover(hchild, 0);
8974 track_query(0, NULL, 0);
8976 flush_events();
8977 flush_sequence();
8979 track_hover(hwnd, 0);
8980 track_query(TME_HOVER, hwnd, default_hover_time);
8982 pump_msg_loop_timeout(default_hover_time, FALSE);
8983 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8985 track_query(0, NULL, 0);
8987 track_hover(hwnd, HOVER_DEFAULT);
8988 track_query(TME_HOVER, hwnd, default_hover_time);
8990 Sleep(default_hover_time / 2);
8991 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8992 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8994 track_query(TME_HOVER, hwnd, default_hover_time);
8996 pump_msg_loop_timeout(default_hover_time / 2, FALSE);
8997 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8999 track_query(0, NULL, 0);
9001 track_hover(hwnd, HOVER_DEFAULT);
9002 track_query(TME_HOVER, hwnd, default_hover_time);
9004 pump_msg_loop_timeout(default_hover_time, TRUE);
9005 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9007 track_query(0, NULL, 0);
9009 track_hover(hwnd, HOVER_DEFAULT);
9010 track_query(TME_HOVER, hwnd, default_hover_time);
9011 track_hover_cancel(hwnd);
9013 DestroyWindow(hwnd);
9015 #undef track_hover
9016 #undef track_query
9017 #undef track_hover_cancel
9021 static const struct message WmSetWindowRgn[] = {
9022 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9023 { WM_NCCALCSIZE, sent|wparam, 1 },
9024 { WM_NCPAINT, sent }, /* wparam != 1 */
9025 { WM_GETTEXT, sent|defwinproc|optional },
9026 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9027 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9028 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9029 { 0 }
9032 static const struct message WmSetWindowRgn_no_redraw[] = {
9033 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9034 { WM_NCCALCSIZE, sent|wparam, 1 },
9035 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9036 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9037 { 0 }
9040 static const struct message WmSetWindowRgn_clear[] = {
9041 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9042 { WM_NCCALCSIZE, sent|wparam, 1 },
9043 { WM_NCPAINT, sent }, /* wparam != 1 */
9044 { WM_GETTEXT, sent|defwinproc|optional },
9045 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9046 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9047 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9048 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9049 { WM_GETTEXT, sent|defwinproc|optional },
9050 { WM_ERASEBKGND, sent|optional },
9051 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9052 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9053 { 0 }
9056 static void test_SetWindowRgn(void)
9058 HRGN hrgn;
9059 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9060 100, 100, 200, 200, 0, 0, 0, NULL);
9061 ok( hwnd != 0, "Failed to create overlapped window\n" );
9063 ShowWindow( hwnd, SW_SHOW );
9064 UpdateWindow( hwnd );
9065 flush_events();
9066 flush_sequence();
9068 trace("testing SetWindowRgn\n");
9069 hrgn = CreateRectRgn( 0, 0, 150, 150 );
9070 SetWindowRgn( hwnd, hrgn, TRUE );
9071 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9073 hrgn = CreateRectRgn( 30, 30, 160, 160 );
9074 SetWindowRgn( hwnd, hrgn, FALSE );
9075 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9077 hrgn = CreateRectRgn( 0, 0, 180, 180 );
9078 SetWindowRgn( hwnd, hrgn, TRUE );
9079 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9081 SetWindowRgn( hwnd, 0, TRUE );
9082 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9084 DestroyWindow( hwnd );
9087 /*************************** ShowWindow() test ******************************/
9088 static const struct message WmShowNormal[] = {
9089 { WM_SHOWWINDOW, sent|wparam, 1 },
9090 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9091 { HCBT_ACTIVATE, hook },
9092 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9093 { HCBT_SETFOCUS, hook },
9094 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9095 { 0 }
9097 static const struct message WmShow[] = {
9098 { WM_SHOWWINDOW, sent|wparam, 1 },
9099 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9100 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9101 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9102 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9103 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9104 { 0 }
9106 static const struct message WmShowNoActivate_1[] = {
9107 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9108 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
9109 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
9110 { WM_MOVE, sent|defwinproc },
9111 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9112 { 0 }
9114 static const struct message WmShowNoActivate_2[] = {
9115 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9116 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9117 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9118 { WM_MOVE, sent|defwinproc },
9119 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9120 { HCBT_SETFOCUS, hook|optional },
9121 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9122 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9123 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9124 { 0 }
9126 static const struct message WmShowNA_1[] = {
9127 { WM_SHOWWINDOW, sent|wparam, 1 },
9128 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9129 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9130 { 0 }
9132 static const struct message WmShowNA_2[] = {
9133 { WM_SHOWWINDOW, sent|wparam, 1 },
9134 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9135 { 0 }
9137 static const struct message WmRestore_1[] = {
9138 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9139 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9140 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9141 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9142 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9143 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9144 { WM_MOVE, sent|defwinproc },
9145 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9146 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9147 { 0 }
9149 static const struct message WmRestore_2[] = {
9150 { WM_SHOWWINDOW, sent|wparam, 1 },
9151 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9152 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9153 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9154 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9155 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9156 { 0 }
9158 static const struct message WmRestore_3[] = {
9159 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9160 { WM_GETMINMAXINFO, sent },
9161 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9162 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9163 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9164 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9165 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9166 { WM_MOVE, sent|defwinproc },
9167 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9168 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9169 { 0 }
9171 static const struct message WmRestore_4[] = {
9172 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9173 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9174 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9175 { WM_MOVE, sent|defwinproc },
9176 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9177 { 0 }
9179 static const struct message WmRestore_5[] = {
9180 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
9181 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9182 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9183 { WM_MOVE, sent|defwinproc },
9184 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9185 { 0 }
9187 static const struct message WmHide_1[] = {
9188 { WM_SHOWWINDOW, sent|wparam, 0 },
9189 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9190 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9191 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9192 { 0 }
9194 static const struct message WmHide_2[] = {
9195 { WM_SHOWWINDOW, sent|wparam, 0 },
9196 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9197 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9198 { 0 }
9200 static const struct message WmHide_3[] = {
9201 { WM_SHOWWINDOW, sent|wparam, 0 },
9202 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9203 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9204 { HCBT_SETFOCUS, hook },
9205 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9206 { 0 }
9208 static const struct message WmShowMinimized_1[] = {
9209 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9210 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9211 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9212 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9213 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9214 { WM_MOVE, sent|defwinproc },
9215 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9216 { 0 }
9218 static const struct message WmMinimize_1[] = {
9219 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9220 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9221 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9222 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9223 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9224 { WM_MOVE, sent|defwinproc },
9225 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9226 { 0 }
9228 static const struct message WmMinimize_2[] = {
9229 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9230 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9231 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9232 { WM_MOVE, sent|defwinproc },
9233 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9234 { 0 }
9236 static const struct message WmMinimize_3[] = {
9237 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9238 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9239 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9240 { WM_MOVE, sent|defwinproc },
9241 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9242 { 0 }
9244 static const struct message WmShowMinNoActivate[] = {
9245 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9246 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9247 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9248 { 0 }
9250 static const struct message WmMinMax_1[] = {
9251 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9252 { 0 }
9254 static const struct message WmMinMax_2[] = {
9255 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9256 { 0 }
9258 static const struct message WmMinMax_3[] = {
9259 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9260 { 0 }
9262 static const struct message WmMinMax_4[] = {
9263 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9264 { 0 }
9266 static const struct message WmShowMaximized_1[] = {
9267 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9268 { WM_GETMINMAXINFO, sent },
9269 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9270 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9271 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9272 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9273 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9274 { WM_MOVE, sent|defwinproc },
9275 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9276 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9277 { 0 }
9279 static const struct message WmShowMaximized_2[] = {
9280 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9281 { WM_GETMINMAXINFO, sent },
9282 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
9283 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9284 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
9285 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
9286 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9287 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9288 { WM_MOVE, sent|defwinproc },
9289 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9290 { HCBT_SETFOCUS, hook },
9291 { 0 }
9293 static const struct message WmShowMaximized_3[] = {
9294 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9295 { WM_GETMINMAXINFO, sent },
9296 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9297 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9298 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9299 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9300 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9301 { WM_MOVE, sent|defwinproc },
9302 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9303 { 0 }
9306 static void test_ShowWindow(void)
9308 /* ShowWindow commands in random order */
9309 static const struct
9311 INT cmd; /* ShowWindow command */
9312 LPARAM ret; /* ShowWindow return value */
9313 DWORD style; /* window style after the command */
9314 const struct message *msg; /* message sequence the command produces */
9315 BOOL todo_msg; /* message sequence doesn't match what Wine does */
9316 } sw[] =
9318 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
9319 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9320 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9321 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9322 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
9323 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
9324 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
9325 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9326 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
9327 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9328 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
9329 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
9330 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
9331 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9332 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
9333 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9334 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
9335 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9336 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
9337 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9338 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9339 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
9340 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
9341 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9342 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9343 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
9344 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
9345 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9346 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9347 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
9348 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9349 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
9350 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9351 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
9352 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
9353 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9354 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
9355 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9356 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9357 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, TRUE },
9358 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9359 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
9360 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9361 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
9362 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9363 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
9364 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
9365 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
9366 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
9367 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
9368 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9369 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9370 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9371 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, TRUE },
9372 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9373 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
9374 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
9376 HWND hwnd;
9377 DWORD style;
9378 LPARAM ret;
9379 INT i;
9381 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
9382 hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
9383 120, 120, 90, 90,
9384 0, 0, 0, NULL);
9385 assert(hwnd);
9387 style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9388 ok(style == 0, "expected style 0, got %08x\n", style);
9390 flush_events();
9391 flush_sequence();
9393 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
9395 static const char * const sw_cmd_name[13] =
9397 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
9398 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
9399 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
9400 "SW_NORMALNA" /* 0xCC */
9402 char comment[64];
9403 INT idx; /* index into the above array of names */
9405 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
9407 style = GetWindowLong(hwnd, GWL_STYLE);
9408 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
9409 ret = ShowWindow(hwnd, sw[i].cmd);
9410 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
9411 style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9412 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
9414 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
9415 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
9417 flush_events();
9418 flush_sequence();
9421 DestroyWindow(hwnd);
9424 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9426 struct message msg;
9428 trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
9430 switch (message)
9432 case WM_WINDOWPOSCHANGING:
9433 case WM_WINDOWPOSCHANGED:
9435 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
9437 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
9438 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
9439 winpos->hwnd, winpos->hwndInsertAfter,
9440 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
9441 dump_winpos_flags(winpos->flags);
9443 /* Log only documented flags, win2k uses 0x1000 and 0x2000
9444 * in the high word for internal purposes
9446 wParam = winpos->flags & 0xffff;
9447 /* We are not interested in the flags that don't match under XP and Win9x */
9448 wParam &= ~(SWP_NOZORDER);
9449 break;
9452 /* explicitly ignore WM_GETICON message */
9453 case WM_GETICON:
9454 return 0;
9457 msg.message = message;
9458 msg.flags = sent|wparam|lparam;
9459 msg.wParam = wParam;
9460 msg.lParam = lParam;
9461 add_message(&msg);
9463 /* calling DefDlgProc leads to a recursion under XP */
9465 switch (message)
9467 case WM_INITDIALOG:
9468 case WM_GETDLGCODE:
9469 return 0;
9471 return 1;
9474 static const struct message WmDefDlgSetFocus_1[] = {
9475 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9476 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9477 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9478 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9479 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9480 { HCBT_SETFOCUS, hook },
9481 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9482 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9483 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9484 { WM_SETFOCUS, sent|wparam, 0 },
9485 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9486 { WM_CTLCOLOREDIT, sent },
9487 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9488 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9489 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9490 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9491 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
9492 { 0 }
9494 static const struct message WmDefDlgSetFocus_2[] = {
9495 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9496 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9497 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9498 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9499 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9500 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9501 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
9502 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9503 { 0 }
9505 /* Creation of a dialog */
9506 static const struct message WmCreateDialogParamSeq_1[] = {
9507 { HCBT_CREATEWND, hook },
9508 { WM_NCCREATE, sent },
9509 { WM_NCCALCSIZE, sent|wparam, 0 },
9510 { WM_CREATE, sent },
9511 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9512 { WM_SIZE, sent|wparam, SIZE_RESTORED },
9513 { WM_MOVE, sent },
9514 { WM_SETFONT, sent },
9515 { WM_INITDIALOG, sent },
9516 { WM_CHANGEUISTATE, sent|optional },
9517 { 0 }
9519 /* Creation of a dialog */
9520 static const struct message WmCreateDialogParamSeq_2[] = {
9521 { HCBT_CREATEWND, hook },
9522 { WM_NCCREATE, sent },
9523 { WM_NCCALCSIZE, sent|wparam, 0 },
9524 { WM_CREATE, sent },
9525 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9526 { WM_SIZE, sent|wparam, SIZE_RESTORED },
9527 { WM_MOVE, sent },
9528 { WM_CHANGEUISTATE, sent|optional },
9529 { 0 }
9532 static void test_dialog_messages(void)
9534 WNDCLASS cls;
9535 HWND hdlg, hedit1, hedit2, hfocus;
9536 LRESULT ret;
9538 #define set_selection(hctl, start, end) \
9539 ret = SendMessage(hctl, EM_SETSEL, start, end); \
9540 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
9542 #define check_selection(hctl, start, end) \
9543 ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
9544 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
9546 subclass_edit();
9548 hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
9549 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
9550 0, 0, 100, 100, 0, 0, 0, NULL);
9551 ok(hdlg != 0, "Failed to create custom dialog window\n");
9553 hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
9554 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9555 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
9556 ok(hedit1 != 0, "Failed to create edit control\n");
9557 hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
9558 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9559 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
9560 ok(hedit2 != 0, "Failed to create edit control\n");
9562 SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
9563 SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
9565 hfocus = GetFocus();
9566 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
9568 SetFocus(hedit2);
9569 hfocus = GetFocus();
9570 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
9572 check_selection(hedit1, 0, 0);
9573 check_selection(hedit2, 0, 0);
9575 set_selection(hedit2, 0, -1);
9576 check_selection(hedit2, 0, 3);
9578 SetFocus(0);
9579 hfocus = GetFocus();
9580 ok(hfocus == 0, "wrong focus %p\n", hfocus);
9582 flush_sequence();
9583 ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9584 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9585 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
9587 hfocus = GetFocus();
9588 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9590 check_selection(hedit1, 0, 5);
9591 check_selection(hedit2, 0, 3);
9593 flush_sequence();
9594 ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9595 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9596 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
9598 hfocus = GetFocus();
9599 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9601 check_selection(hedit1, 0, 5);
9602 check_selection(hedit2, 0, 3);
9604 EndDialog(hdlg, 0);
9605 DestroyWindow(hedit1);
9606 DestroyWindow(hedit2);
9607 DestroyWindow(hdlg);
9608 flush_sequence();
9610 #undef set_selection
9611 #undef check_selection
9613 ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
9614 cls.lpszClassName = "MyDialogClass";
9615 cls.hInstance = GetModuleHandle(0);
9616 /* need a cast since a dlgproc is used as a wndproc */
9617 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
9618 if (!RegisterClass(&cls)) assert(0);
9620 hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
9621 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9622 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
9623 EndDialog(hdlg, 0);
9624 DestroyWindow(hdlg);
9625 flush_sequence();
9627 hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
9628 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9629 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
9630 EndDialog(hdlg, 0);
9631 DestroyWindow(hdlg);
9632 flush_sequence();
9634 UnregisterClass(cls.lpszClassName, cls.hInstance);
9637 static void test_nullCallback(void)
9639 HWND hwnd;
9641 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9642 100, 100, 200, 200, 0, 0, 0, NULL);
9643 ok (hwnd != 0, "Failed to create overlapped window\n");
9645 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
9646 flush_events();
9647 DestroyWindow(hwnd);
9650 static const struct message SetForegroundWindowSeq[] =
9652 { WM_NCACTIVATE, sent|wparam, 0 },
9653 { WM_GETTEXT, sent|defwinproc|optional },
9654 { WM_ACTIVATE, sent|wparam, 0 },
9655 { WM_ACTIVATEAPP, sent|wparam, 0 },
9656 { WM_KILLFOCUS, sent },
9657 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9658 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
9659 { 0 }
9662 static void test_SetForegroundWindow(void)
9664 HWND hwnd;
9666 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
9667 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9668 100, 100, 200, 200, 0, 0, 0, NULL);
9669 ok (hwnd != 0, "Failed to create overlapped window\n");
9670 flush_sequence();
9672 trace("SetForegroundWindow( 0 )\n");
9673 SetForegroundWindow( 0 );
9674 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
9675 trace("SetForegroundWindow( GetDesktopWindow() )\n");
9676 SetForegroundWindow( GetDesktopWindow() );
9677 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
9678 "foreground top level window", FALSE);
9679 trace("done\n");
9681 DestroyWindow(hwnd);
9684 static void test_dbcs_wm_char(void)
9686 BYTE dbch[2];
9687 WCHAR wch, bad_wch;
9688 HWND hwnd, hwnd2;
9689 MSG msg;
9690 DWORD time;
9691 POINT pt;
9692 DWORD_PTR res;
9693 CPINFOEXA cpinfo;
9694 UINT i, j, k;
9695 struct message wmCharSeq[2];
9697 if (!pGetCPInfoExA)
9699 skip("GetCPInfoExA is not available\n");
9700 return;
9703 pGetCPInfoExA( CP_ACP, 0, &cpinfo );
9704 if (cpinfo.MaxCharSize != 2)
9706 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
9707 return;
9710 dbch[0] = dbch[1] = 0;
9711 wch = 0;
9712 bad_wch = cpinfo.UnicodeDefaultChar;
9713 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
9714 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
9715 for (k = 128; k <= 255; k++)
9717 char str[2];
9718 WCHAR wstr[2];
9719 str[0] = j;
9720 str[1] = k;
9721 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
9722 WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
9723 (BYTE)str[0] == j && (BYTE)str[1] == k &&
9724 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
9726 dbch[0] = j;
9727 dbch[1] = k;
9728 wch = wstr[0];
9729 break;
9733 if (!wch)
9735 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
9736 return;
9738 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
9739 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
9741 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
9742 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9743 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
9744 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9745 ok (hwnd != 0, "Failed to create overlapped window\n");
9746 ok (hwnd2 != 0, "Failed to create overlapped window\n");
9747 flush_sequence();
9749 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
9750 wmCharSeq[0].message = WM_CHAR;
9751 wmCharSeq[0].flags = sent|wparam;
9752 wmCharSeq[0].wParam = wch;
9754 /* posted message */
9755 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9756 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9757 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9758 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9759 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9760 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9761 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9763 /* posted thread message */
9764 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
9765 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9766 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9767 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9768 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9769 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9770 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9772 /* sent message */
9773 flush_sequence();
9774 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9775 ok_sequence( WmEmptySeq, "no messages", FALSE );
9776 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9777 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9778 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9780 /* sent message with timeout */
9781 flush_sequence();
9782 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
9783 ok_sequence( WmEmptySeq, "no messages", FALSE );
9784 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
9785 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9786 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9788 /* sent message with timeout and callback */
9789 flush_sequence();
9790 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
9791 ok_sequence( WmEmptySeq, "no messages", FALSE );
9792 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
9793 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9794 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9796 /* sent message with callback */
9797 flush_sequence();
9798 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9799 ok_sequence( WmEmptySeq, "no messages", FALSE );
9800 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
9801 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9802 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9804 /* direct window proc call */
9805 flush_sequence();
9806 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9807 ok_sequence( WmEmptySeq, "no messages", FALSE );
9808 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9809 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9811 /* dispatch message */
9812 msg.hwnd = hwnd;
9813 msg.message = WM_CHAR;
9814 msg.wParam = dbch[0];
9815 msg.lParam = 0;
9816 DispatchMessageA( &msg );
9817 ok_sequence( WmEmptySeq, "no messages", FALSE );
9818 msg.wParam = dbch[1];
9819 DispatchMessageA( &msg );
9820 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9822 /* window handle is irrelevant */
9823 flush_sequence();
9824 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9825 ok_sequence( WmEmptySeq, "no messages", FALSE );
9826 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9827 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9828 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9830 /* interleaved post and send */
9831 flush_sequence();
9832 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9833 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9834 ok_sequence( WmEmptySeq, "no messages", FALSE );
9835 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9836 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9837 ok_sequence( WmEmptySeq, "no messages", FALSE );
9838 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9839 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9840 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9841 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9842 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9843 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9844 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9846 /* interleaved sent message and winproc */
9847 flush_sequence();
9848 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9849 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9850 ok_sequence( WmEmptySeq, "no messages", FALSE );
9851 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9852 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9853 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9854 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9856 /* interleaved winproc and dispatch */
9857 msg.hwnd = hwnd;
9858 msg.message = WM_CHAR;
9859 msg.wParam = dbch[0];
9860 msg.lParam = 0;
9861 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9862 DispatchMessageA( &msg );
9863 ok_sequence( WmEmptySeq, "no messages", FALSE );
9864 msg.wParam = dbch[1];
9865 DispatchMessageA( &msg );
9866 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9867 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9868 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9870 /* interleaved sends */
9871 flush_sequence();
9872 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9873 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
9874 ok_sequence( WmEmptySeq, "no messages", FALSE );
9875 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
9876 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9877 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9878 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9880 /* dbcs WM_CHAR */
9881 flush_sequence();
9882 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
9883 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9884 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9886 /* other char messages are not magic */
9887 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
9888 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9889 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
9890 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
9891 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9892 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
9893 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9894 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
9895 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
9896 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9898 /* test retrieving messages */
9900 PostMessageW( hwnd, WM_CHAR, wch, 0 );
9901 ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9902 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9903 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9904 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9905 ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9906 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9907 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9908 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9909 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9911 /* message filters */
9912 PostMessageW( hwnd, WM_CHAR, wch, 0 );
9913 ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9914 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9915 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9916 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9917 /* message id is filtered, hwnd is not */
9918 ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
9919 ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
9920 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9921 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9922 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9923 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9925 /* mixing GetMessage and PostMessage */
9926 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
9927 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
9928 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9929 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9930 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9931 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
9932 time = msg.time;
9933 pt = msg.pt;
9934 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
9935 ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9936 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9937 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9938 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9939 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
9940 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
9941 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 );
9942 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9944 /* without PM_REMOVE */
9945 PostMessageW( hwnd, WM_CHAR, wch, 0 );
9946 ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
9947 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9948 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9949 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9950 ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9951 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9952 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9953 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9954 ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
9955 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9956 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9957 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9958 ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9959 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9960 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9961 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9962 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9964 DestroyWindow(hwnd);
9967 #define ID_LISTBOX 0x000f
9969 static const struct message wm_lb_setcursel_0[] =
9971 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
9972 { WM_CTLCOLORLISTBOX, sent|parent },
9973 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
9974 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
9975 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
9976 { 0 }
9978 static const struct message wm_lb_setcursel_1[] =
9980 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
9981 { WM_CTLCOLORLISTBOX, sent|parent },
9982 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
9983 { WM_CTLCOLORLISTBOX, sent|parent },
9984 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
9985 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
9986 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
9987 { 0 }
9989 static const struct message wm_lb_setcursel_2[] =
9991 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
9992 { WM_CTLCOLORLISTBOX, sent|parent },
9993 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
9994 { WM_CTLCOLORLISTBOX, sent|parent },
9995 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
9996 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
9997 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
9998 { 0 }
10000 static const struct message wm_lb_click_0[] =
10002 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
10003 { HCBT_SETFOCUS, hook },
10004 { WM_KILLFOCUS, sent|parent },
10005 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
10006 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10007 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10008 { WM_SETFOCUS, sent },
10010 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
10011 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
10012 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10013 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
10014 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10016 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
10017 { WM_CTLCOLORLISTBOX, sent|parent },
10018 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
10019 { WM_CTLCOLORLISTBOX, sent|parent },
10020 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10021 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
10023 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10024 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10026 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10027 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10028 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, 0 },
10029 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
10030 { 0 }
10033 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
10035 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
10037 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10039 struct message msg;
10041 /* do not log painting messages */
10042 if (message != WM_PAINT &&
10043 message != WM_NCPAINT &&
10044 message != WM_SYNCPAINT &&
10045 message != WM_ERASEBKGND &&
10046 message != WM_NCHITTEST &&
10047 message != WM_GETTEXT &&
10048 message != WM_GETICON &&
10049 message != WM_DEVICECHANGE)
10051 trace("listbox: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
10053 msg.message = message;
10054 msg.flags = sent|wparam|lparam;
10055 msg.wParam = wp;
10056 msg.lParam = lp;
10057 add_message(&msg);
10060 return CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
10063 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
10064 int caret_index, int top_index, int line)
10066 LRESULT ret;
10068 /* calling an orig proc helps to avoid unnecessary message logging */
10069 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
10070 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
10071 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
10072 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
10073 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
10074 ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
10075 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
10076 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
10079 static void test_listbox(void)
10081 HWND parent, listbox;
10082 LRESULT ret;
10084 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10085 100, 100, 200, 200, 0, 0, 0, NULL);
10086 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
10087 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
10088 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
10089 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
10091 check_lb_state(listbox, 0, LB_ERR, 0, 0);
10093 ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
10094 ok(ret == 0, "expected 0, got %ld\n", ret);
10095 ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
10096 ok(ret == 1, "expected 1, got %ld\n", ret);
10097 ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
10098 ok(ret == 2, "expected 2, got %ld\n", ret);
10100 check_lb_state(listbox, 3, LB_ERR, 0, 0);
10102 flush_sequence();
10104 log_all_parent_messages++;
10106 trace("selecting item 0\n");
10107 ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
10108 ok(ret == 0, "expected 0, got %ld\n", ret);
10109 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
10110 check_lb_state(listbox, 3, 0, 0, 0);
10111 flush_sequence();
10113 trace("selecting item 1\n");
10114 ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
10115 ok(ret == 1, "expected 1, got %ld\n", ret);
10116 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
10117 check_lb_state(listbox, 3, 1, 1, 0);
10119 trace("selecting item 2\n");
10120 ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
10121 ok(ret == 2, "expected 2, got %ld\n", ret);
10122 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
10123 check_lb_state(listbox, 3, 2, 2, 0);
10125 trace("clicking on item 0\n");
10126 ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
10127 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10128 ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
10129 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10130 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
10131 check_lb_state(listbox, 3, 0, 0, 0);
10132 flush_sequence();
10134 log_all_parent_messages--;
10136 DestroyWindow(parent);
10139 START_TEST(msg)
10141 BOOL ret;
10142 FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
10144 init_procs();
10146 if (!RegisterWindowClasses()) assert(0);
10148 if (pSetWinEventHook)
10150 hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
10151 GetModuleHandleA(0),
10152 win_event_proc,
10154 GetCurrentThreadId(),
10155 WINEVENT_INCONTEXT);
10156 assert(hEvent_hook);
10158 if (pIsWinEventHookInstalled)
10160 UINT event;
10161 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
10162 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
10166 cbt_hook_thread_id = GetCurrentThreadId();
10167 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
10168 assert(hCBT_hook);
10170 test_winevents();
10172 /* Fix message sequences before removing 4 lines below */
10173 #if 1
10174 if (pUnhookWinEvent && hEvent_hook)
10176 ret = pUnhookWinEvent(hEvent_hook);
10177 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10178 pUnhookWinEvent = 0;
10180 hEvent_hook = 0;
10181 #endif
10183 test_ShowWindow();
10184 test_PeekMessage();
10185 test_PeekMessage2();
10186 test_scrollwindowex();
10187 test_messages();
10188 test_showwindow();
10189 invisible_parent_tests();
10190 test_mdi_messages();
10191 test_button_messages();
10192 test_static_messages();
10193 test_paint_messages();
10194 test_interthread_messages();
10195 test_message_conversion();
10196 test_accelerators();
10197 test_timers();
10198 test_timers_no_wnd();
10199 test_set_hook();
10200 test_DestroyWindow();
10201 test_DispatchMessage();
10202 test_SendMessageTimeout();
10203 test_edit_messages();
10204 test_quit_message();
10206 if (!pTrackMouseEvent)
10207 skip("TrackMouseEvent is not available\n");
10208 else
10209 test_TrackMouseEvent();
10211 test_SetWindowRgn();
10212 test_sys_menu();
10213 test_dialog_messages();
10214 test_nullCallback();
10215 test_SetForegroundWindow();
10216 test_dbcs_wm_char();
10217 test_listbox();
10219 UnhookWindowsHookEx(hCBT_hook);
10220 if (pUnhookWinEvent)
10222 ret = pUnhookWinEvent(hEvent_hook);
10223 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10224 SetLastError(0xdeadbeef);
10225 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
10226 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10227 GetLastError() == 0xdeadbeef, /* Win9x */
10228 "unexpected error %d\n", GetLastError());
10230 else
10231 skip("UnhookWinEvent is not available\n");