sync to trunk revision 36100
[reactos.git] / rostests / winetests / user32 / msg.c
1 /*
2 * Unit tests for window message handling
3 *
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004, 2005 Dmitry Timoshkov
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "wine/winuser.h"
31 #include "winuser.h"
32 #include "winnls.h"
33
34 #include "wine/test.h"
35
36 #define MDI_FIRST_CHILD_ID 2004
37
38 /* undocumented SWP flags - from SDK 3.1 */
39 #define SWP_NOCLIENTSIZE 0x0800
40 #define SWP_NOCLIENTMOVE 0x1000
41 #define SWP_STATECHANGED 0x8000
42
43 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
44
45 #ifndef WM_KEYF1
46 #define WM_KEYF1 0x004d
47 #endif
48
49 #ifndef WM_SYSTIMER
50 #define WM_SYSTIMER 0x0118
51 #endif
52
53 #define WND_PARENT_ID 1
54 #define WND_POPUP_ID 2
55 #define WND_CHILD_ID 3
56
57 #ifndef WM_LBTRACKPOINT
58 #define WM_LBTRACKPOINT 0x0131
59 #endif
60
61 /* encoded DRAWITEMSTRUCT into an LPARAM */
62 typedef struct
63 {
64 union
65 {
66 struct
67 {
68 UINT type : 4; /* ODT_* flags */
69 UINT ctl_id : 4; /* Control ID */
70 UINT item_id : 4; /* Menu item ID */
71 UINT action : 4; /* ODA_* flags */
72 UINT state : 16; /* ODS_* flags */
73 } item;
74 LPARAM lp;
75 } u;
76 } DRAW_ITEM_STRUCT;
77
78 static BOOL test_DestroyWindow_flag;
79 static HWINEVENTHOOK hEvent_hook;
80
81 static void dump_winpos_flags(UINT flags);
82
83 static const WCHAR testWindowClassW[] =
84 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
85
86 /*
87 FIXME: add tests for these
88 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
89 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
90 WS_THICKFRAME: thick border
91 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
92 WS_BORDER (default for overlapped windows): single black border
93 none (default for child (and popup?) windows): no border
94 */
95
96 typedef enum {
97 sent=0x1,
98 posted=0x2,
99 parent=0x4,
100 wparam=0x8,
101 lparam=0x10,
102 defwinproc=0x20,
103 beginpaint=0x40,
104 optional=0x80,
105 hook=0x100,
106 winevent_hook=0x200
107 } msg_flags_t;
108
109 struct message {
110 UINT message; /* the WM_* code */
111 msg_flags_t flags; /* message props */
112 WPARAM wParam; /* expected value of wParam */
113 LPARAM lParam; /* expected value of lParam */
114 };
115
116 /* Empty message sequence */
117 static const struct message WmEmptySeq[] =
118 {
119 { 0 }
120 };
121 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
122 static const struct message WmCreateOverlappedSeq[] = {
123 { HCBT_CREATEWND, hook },
124 { WM_GETMINMAXINFO, sent },
125 { WM_NCCREATE, sent },
126 { WM_NCCALCSIZE, sent|wparam, 0 },
127 { 0x0093, sent|defwinproc|optional },
128 { 0x0094, sent|defwinproc|optional },
129 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
130 { WM_CREATE, sent },
131 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
132 { 0 }
133 };
134 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
135 * for a not visible overlapped window.
136 */
137 static const struct message WmSWP_ShowOverlappedSeq[] = {
138 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
139 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
140 { WM_NCPAINT, sent|wparam|optional, 1 },
141 { WM_GETTEXT, sent|defwinproc|optional },
142 { WM_ERASEBKGND, sent|optional },
143 { HCBT_ACTIVATE, hook },
144 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
145 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
146 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
147 { WM_ACTIVATEAPP, sent|wparam, 1 },
148 { WM_NCACTIVATE, sent|wparam, 1 },
149 { WM_GETTEXT, sent|defwinproc|optional },
150 { WM_ACTIVATE, sent|wparam, 1 },
151 { HCBT_SETFOCUS, hook },
152 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
153 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
154 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
155 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
156 { WM_NCPAINT, sent|wparam|optional, 1 },
157 { WM_GETTEXT, sent|defwinproc|optional },
158 { WM_ERASEBKGND, sent|optional },
159 /* Win9x adds SWP_NOZORDER below */
160 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
161 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
162 { WM_NCPAINT, sent|wparam|optional, 1 },
163 { WM_ERASEBKGND, sent|optional },
164 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
165 { 0 }
166 };
167 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
168 * for a visible overlapped window.
169 */
170 static const struct message WmSWP_HideOverlappedSeq[] = {
171 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
172 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
173 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
174 { 0 }
175 };
176
177 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
178 * for a visible overlapped window.
179 */
180 static const struct message WmSWP_ResizeSeq[] = {
181 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
182 { WM_GETMINMAXINFO, sent|defwinproc },
183 { WM_NCCALCSIZE, sent|wparam, TRUE },
184 { WM_NCPAINT, sent|optional },
185 { WM_GETTEXT, sent|defwinproc|optional },
186 { WM_ERASEBKGND, sent|optional },
187 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
188 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
189 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
190 { WM_NCPAINT, sent|optional },
191 { WM_GETTEXT, sent|defwinproc|optional },
192 { WM_ERASEBKGND, sent|optional },
193 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
194 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
195 { 0 }
196 };
197
198 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
199 * for a visible popup window.
200 */
201 static const struct message WmSWP_ResizePopupSeq[] = {
202 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
203 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
204 { WM_NCCALCSIZE, sent|wparam, TRUE },
205 { WM_NCPAINT, sent|optional },
206 { WM_GETTEXT, sent|defwinproc|optional },
207 { WM_ERASEBKGND, sent|optional },
208 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
209 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
210 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
211 { WM_NCPAINT, sent|optional },
212 { WM_GETTEXT, sent|defwinproc|optional },
213 { WM_ERASEBKGND, sent|optional },
214 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
215 { 0 }
216 };
217
218 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
219 * for a visible overlapped window.
220 */
221 static const struct message WmSWP_MoveSeq[] = {
222 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
223 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
224 { WM_MOVE, sent|defwinproc|wparam, 0 },
225 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
226 { 0 }
227 };
228 /* Resize with SetWindowPos(SWP_NOZORDER)
229 * for a visible overlapped window
230 * SWP_NOZORDER is stripped by the logging code
231 */
232 static const struct message WmSWP_ResizeNoZOrder[] = {
233 { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ },
234 { WM_GETMINMAXINFO, sent|defwinproc },
235 { WM_NCCALCSIZE, sent|wparam, 1 },
236 { WM_NCPAINT, sent },
237 { WM_GETTEXT, sent|defwinproc|optional },
238 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
239 { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE },
240 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
241 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
242 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
243 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
244 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
245 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
246 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
247 { 0 }
248 };
249
250 /* Switch visible mdi children */
251 static const struct message WmSwitchChild[] = {
252 /* Switch MDI child */
253 { WM_MDIACTIVATE, sent },/* in the MDI client */
254 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
255 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
256 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
257 /* Deactivate 2nd MDI child */
258 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
259 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
260 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
261 /* Preparing for maximize and maximaze the 1st MDI child */
262 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
263 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
264 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
265 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
266 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
267 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
268 /* Lock redraw 2nd MDI child */
269 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
270 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
271 /* Restore 2nd MDI child */
272 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
273 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
274 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
275 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
276 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
277 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
278 /* Redraw 2nd MDI child */
279 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
280 /* Redraw MDI frame */
281 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
282 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
283 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
284 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
285 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
286 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
287 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
288 { HCBT_SETFOCUS, hook },
289 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
290 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
291 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
292 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
293 { WM_SETFOCUS, sent },/* in the MDI client */
294 { HCBT_SETFOCUS, hook },
295 { WM_KILLFOCUS, sent },/* in the MDI client */
296 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
297 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
298 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
299 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
300 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
301 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
302 { 0 }
303 };
304
305 /* Switch visible not maximized mdi children */
306 static const struct message WmSwitchNotMaximizedChild[] = {
307 /* Switch not maximized MDI child */
308 { WM_MDIACTIVATE, sent },/* in the MDI client */
309 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
310 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
311 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
312 /* Deactivate 1st MDI child */
313 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
314 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
315 /* Activate 2nd MDI child */
316 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
317 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
318 { WM_SETVISIBLE, hook }, /* in the 1st MDI child */
319 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
320 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
321 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
322 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
323 { WM_SETVISIBLE, hook },
324 { WM_KILLFOCUS, sent }, /* in the MDI client */
325 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
326 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
327 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
328 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
329 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
330 { 0 }
331 };
332
333
334 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
335 SWP_NOZORDER|SWP_FRAMECHANGED)
336 * for a visible overlapped window with WS_CLIPCHILDREN style set.
337 */
338 static const struct message WmSWP_FrameChanged_clip[] = {
339 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
340 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
341 { WM_NCPAINT, sent|parent }, /* wparam != 1 */
342 { WM_GETTEXT, sent|parent|defwinproc|optional },
343 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
344 { WM_NCPAINT, sent }, /* wparam != 1 */
345 { WM_ERASEBKGND, sent },
346 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
347 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
348 { WM_PAINT, sent },
349 { 0 }
350 };
351 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
352 SWP_NOZORDER|SWP_FRAMECHANGED)
353 * for a visible overlapped window.
354 */
355 static const struct message WmSWP_FrameChangedDeferErase[] = {
356 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
357 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
358 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
359 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
360 { WM_PAINT, sent|parent },
361 { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
362 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
363 { WM_PAINT, sent },
364 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
365 { WM_ERASEBKGND, sent|beginpaint },
366 { 0 }
367 };
368
369 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
370 SWP_NOZORDER|SWP_FRAMECHANGED)
371 * for a visible overlapped window without WS_CLIPCHILDREN style set.
372 */
373 static const struct message WmSWP_FrameChanged_noclip[] = {
374 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
375 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
376 { WM_NCPAINT, sent|parent }, /* wparam != 1 */
377 { WM_GETTEXT, sent|parent|defwinproc|optional },
378 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
379 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
380 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
381 { WM_PAINT, sent },
382 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
383 { WM_ERASEBKGND, sent|beginpaint },
384 { 0 }
385 };
386
387 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
388 static const struct message WmShowOverlappedSeq[] = {
389 { WM_SHOWWINDOW, sent|wparam, 1 },
390 { WM_NCPAINT, sent|wparam|optional, 1 },
391 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
392 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
393 { WM_NCPAINT, sent|wparam|optional, 1 },
394 { WM_GETTEXT, sent|defwinproc|optional },
395 { WM_ERASEBKGND, sent|optional },
396 { HCBT_ACTIVATE, hook },
397 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
398 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
399 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
400 { WM_NCPAINT, sent|wparam|optional, 1 },
401 { WM_ACTIVATEAPP, sent|wparam, 1 },
402 { WM_NCACTIVATE, sent|wparam, 1 },
403 { WM_GETTEXT, sent|defwinproc|optional },
404 { WM_ACTIVATE, sent|wparam, 1 },
405 { HCBT_SETFOCUS, hook },
406 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
407 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
408 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
409 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
410 { WM_NCPAINT, sent|wparam|optional, 1 },
411 { WM_GETTEXT, sent|defwinproc|optional },
412 { WM_ERASEBKGND, sent|optional },
413 /* Win9x adds SWP_NOZORDER below */
414 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
415 { WM_NCCALCSIZE, sent|optional },
416 { WM_NCPAINT, sent|optional },
417 { WM_ERASEBKGND, sent|optional },
418 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
419 * messages. Does that mean that CreateWindow doesn't set initial
420 * window dimensions for overlapped windows?
421 */
422 { WM_SIZE, sent },
423 { WM_MOVE, sent },
424 #endif
425 { 0 }
426 };
427 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
428 static const struct message WmShowMaxOverlappedSeq[] = {
429 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
430 { WM_GETMINMAXINFO, sent },
431 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
432 { WM_GETMINMAXINFO, sent|defwinproc },
433 { WM_NCCALCSIZE, sent|wparam, TRUE },
434 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
435 { HCBT_ACTIVATE, hook },
436 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
437 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
438 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
439 { WM_ACTIVATEAPP, sent|wparam, 1 },
440 { WM_NCACTIVATE, sent|wparam, 1 },
441 { WM_GETTEXT, sent|defwinproc|optional },
442 { WM_ACTIVATE, sent|wparam, 1 },
443 { HCBT_SETFOCUS, hook },
444 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
445 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
446 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
447 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
448 { WM_NCPAINT, sent|wparam|optional, 1 },
449 { WM_GETTEXT, sent|defwinproc|optional },
450 { WM_ERASEBKGND, sent|optional },
451 /* Win9x adds SWP_NOZORDER below */
452 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
453 { WM_MOVE, sent|defwinproc },
454 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
455 { WM_NCCALCSIZE, sent|optional },
456 { WM_NCPAINT, sent|optional },
457 { WM_ERASEBKGND, sent|optional },
458 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
459 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
460 { 0 }
461 };
462 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
463 static const struct message WmShowMinOverlappedSeq[] = {
464 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
465 { HCBT_SETFOCUS, hook },
466 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
467 { WM_KILLFOCUS, sent },
468 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
469 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
470 { WM_GETTEXT, sent|optional },
471 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
472 { WM_GETMINMAXINFO, sent|defwinproc },
473 { WM_NCCALCSIZE, sent|wparam, TRUE },
474 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
475 { WM_NCPAINT, sent },
476 { WM_GETTEXT, sent|defwinproc|optional },
477 { WM_WINDOWPOSCHANGED, sent },
478 { WM_MOVE, sent|defwinproc },
479 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
480 { WM_NCCALCSIZE, sent|optional },
481 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
482 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
483 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
484 { WM_NCACTIVATE, sent|wparam, 0 },
485 { WM_GETTEXT, sent|defwinproc|optional },
486 { WM_ACTIVATE, sent },
487 { WM_ACTIVATEAPP, sent|wparam, 0 },
488 { 0 }
489 };
490 /* ShowWindow(SW_HIDE) for a visible overlapped window */
491 static const struct message WmHideOverlappedSeq[] = {
492 { WM_SHOWWINDOW, sent|wparam, 0 },
493 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
494 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
495 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
496 { WM_SIZE, sent|optional }, /* XP doesn't send it */
497 { WM_MOVE, sent|optional }, /* XP doesn't send it */
498 { WM_NCACTIVATE, sent|wparam, 0 },
499 { WM_ACTIVATE, sent|wparam, 0 },
500 { WM_ACTIVATEAPP, sent|wparam, 0 },
501 { WM_KILLFOCUS, sent|wparam, 0 },
502 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
503 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
504 { 0 }
505 };
506 /* DestroyWindow for a visible overlapped window */
507 static const struct message WmDestroyOverlappedSeq[] = {
508 { HCBT_DESTROYWND, hook },
509 { 0x0090, sent|optional },
510 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
511 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
512 { 0x0090, sent|optional },
513 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
514 { WM_NCACTIVATE, sent|wparam, 0 },
515 { WM_ACTIVATE, sent|wparam, 0 },
516 { WM_ACTIVATEAPP, sent|wparam, 0 },
517 { WM_KILLFOCUS, sent|wparam, 0 },
518 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
519 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
520 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
521 { WM_DESTROY, sent },
522 { WM_NCDESTROY, sent },
523 { 0 }
524 };
525 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
526 static const struct message WmCreateMaxPopupSeq[] = {
527 { HCBT_CREATEWND, hook },
528 { WM_NCCREATE, sent },
529 { WM_NCCALCSIZE, sent|wparam, 0 },
530 { WM_CREATE, sent },
531 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
532 { WM_SIZE, sent|wparam, SIZE_RESTORED },
533 { WM_MOVE, sent },
534 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
535 { WM_GETMINMAXINFO, sent },
536 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
537 { WM_NCCALCSIZE, sent|wparam, TRUE },
538 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
539 { WM_MOVE, sent|defwinproc },
540 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
541 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
542 { WM_SHOWWINDOW, sent|wparam, 1 },
543 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
544 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
545 { HCBT_ACTIVATE, hook },
546 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
547 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
548 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
549 { WM_ACTIVATEAPP, sent|wparam, 1 },
550 { WM_NCACTIVATE, sent|wparam, 1 },
551 { WM_ACTIVATE, sent|wparam, 1 },
552 { HCBT_SETFOCUS, hook },
553 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
554 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
555 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
556 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
557 { WM_SYNCPAINT, sent|wparam|optional, 4 },
558 { WM_NCPAINT, sent|wparam|optional, 1 },
559 { WM_ERASEBKGND, sent|optional },
560 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
561 { 0 }
562 };
563 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
564 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
565 { HCBT_CREATEWND, hook },
566 { WM_NCCREATE, sent },
567 { WM_NCCALCSIZE, sent|wparam, 0 },
568 { WM_CREATE, sent },
569 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
570 { WM_SIZE, sent|wparam, SIZE_RESTORED },
571 { WM_MOVE, sent },
572 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
573 { WM_GETMINMAXINFO, sent },
574 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
575 { WM_NCCALCSIZE, sent|wparam, TRUE },
576 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
577 { WM_MOVE, sent|defwinproc },
578 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
579 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
580 { 0 }
581 };
582 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
583 static const struct message WmShowMaxPopupResizedSeq[] = {
584 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
585 { WM_GETMINMAXINFO, sent },
586 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
587 { WM_NCCALCSIZE, sent|wparam, TRUE },
588 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
589 { HCBT_ACTIVATE, hook },
590 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
591 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
592 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
593 { WM_ACTIVATEAPP, sent|wparam, 1 },
594 { WM_NCACTIVATE, sent|wparam, 1 },
595 { WM_ACTIVATE, sent|wparam, 1 },
596 { HCBT_SETFOCUS, hook },
597 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
598 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
599 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
600 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
601 { WM_NCPAINT, sent|wparam|optional, 1 },
602 { WM_ERASEBKGND, sent|optional },
603 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE },
604 /* WinNT4.0 sends WM_MOVE */
605 { WM_MOVE, sent|defwinproc|optional },
606 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
607 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
608 { 0 }
609 };
610 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
611 static const struct message WmShowMaxPopupSeq[] = {
612 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
613 { WM_GETMINMAXINFO, sent },
614 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
615 { WM_NCCALCSIZE, sent|wparam, TRUE },
616 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
617 { HCBT_ACTIVATE, hook },
618 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
619 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
620 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
621 { WM_ACTIVATEAPP, sent|wparam, 1 },
622 { WM_NCACTIVATE, sent|wparam, 1 },
623 { WM_ACTIVATE, sent|wparam, 1 },
624 { HCBT_SETFOCUS, hook },
625 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
626 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
627 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
628 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
629 { WM_SYNCPAINT, sent|wparam|optional, 4 },
630 { WM_NCPAINT, sent|wparam|optional, 1 },
631 { WM_ERASEBKGND, sent|optional },
632 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
633 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
634 { 0 }
635 };
636 /* CreateWindow(WS_VISIBLE) for popup window */
637 static const struct message WmCreatePopupSeq[] = {
638 { HCBT_CREATEWND, hook },
639 { WM_NCCREATE, sent },
640 { WM_NCCALCSIZE, sent|wparam, 0 },
641 { WM_CREATE, sent },
642 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
643 { WM_SIZE, sent|wparam, SIZE_RESTORED },
644 { WM_MOVE, sent },
645 { WM_SHOWWINDOW, sent|wparam, 1 },
646 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
647 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
648 { HCBT_ACTIVATE, hook },
649 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
650 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
651 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
652 { WM_NCPAINT, sent|wparam|optional, 1 },
653 { WM_ERASEBKGND, sent|optional },
654 { WM_ACTIVATEAPP, sent|wparam, 1 },
655 { WM_NCACTIVATE, sent|wparam, 1 },
656 { WM_ACTIVATE, sent|wparam, 1 },
657 { HCBT_SETFOCUS, hook },
658 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
659 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
660 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
661 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
662 { WM_SYNCPAINT, sent|wparam|optional, 4 },
663 { WM_NCPAINT, sent|wparam|optional, 1 },
664 { WM_ERASEBKGND, sent|optional },
665 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
666 { 0 }
667 };
668 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
669 static const struct message WmShowVisMaxPopupSeq[] = {
670 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
671 { WM_GETMINMAXINFO, sent },
672 { WM_GETTEXT, sent|optional },
673 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
674 { WM_NCCALCSIZE, sent|wparam, TRUE },
675 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
676 { WM_NCPAINT, sent|wparam|optional, 1 },
677 { WM_ERASEBKGND, sent|optional },
678 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
679 { WM_MOVE, sent|defwinproc },
680 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
681 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
682 { 0 }
683 };
684 /* CreateWindow (for a child popup window, not initially visible) */
685 static const struct message WmCreateChildPopupSeq[] = {
686 { HCBT_CREATEWND, hook },
687 { WM_NCCREATE, sent },
688 { WM_NCCALCSIZE, sent|wparam, 0 },
689 { WM_CREATE, sent },
690 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
691 { WM_SIZE, sent|wparam, SIZE_RESTORED },
692 { WM_MOVE, sent },
693 { 0 }
694 };
695 /* CreateWindow (for a popup window, not initially visible,
696 * which sets WS_VISIBLE in WM_CREATE handler)
697 */
698 static const struct message WmCreateInvisiblePopupSeq[] = {
699 { HCBT_CREATEWND, hook },
700 { WM_NCCREATE, sent },
701 { WM_NCCALCSIZE, sent|wparam, 0 },
702 { WM_CREATE, sent },
703 { WM_STYLECHANGING, sent },
704 { WM_STYLECHANGED, sent },
705 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
706 { WM_SIZE, sent|wparam, SIZE_RESTORED },
707 { WM_MOVE, sent },
708 { 0 }
709 };
710 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
711 * for a popup window with WS_VISIBLE style set
712 */
713 static const struct message WmShowVisiblePopupSeq_2[] = {
714 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
715 { 0 }
716 };
717 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
718 * for a popup window with WS_VISIBLE style set
719 */
720 static const struct message WmShowVisiblePopupSeq_3[] = {
721 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
722 { HCBT_ACTIVATE, hook },
723 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
724 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
725 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
726 { WM_NCACTIVATE, sent|wparam, 1 },
727 { WM_ACTIVATE, sent|wparam, 1 },
728 { HCBT_SETFOCUS, hook },
729 { WM_KILLFOCUS, sent|parent },
730 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
731 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
732 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
733 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
734 { WM_SETFOCUS, sent|defwinproc },
735 { 0 }
736 };
737 /* CreateWindow (for child window, not initially visible) */
738 static const struct message WmCreateChildSeq[] = {
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 { WM_CREATE, sent },
744 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
745 { WM_SIZE, sent|wparam, SIZE_RESTORED },
746 { WM_MOVE, sent },
747 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
748 { 0 }
749 };
750 /* CreateWindow (for maximized child window, not initially visible) */
751 static const struct message WmCreateMaximizedChildSeq[] = {
752 { HCBT_CREATEWND, hook },
753 { WM_NCCREATE, sent },
754 { WM_NCCALCSIZE, sent|wparam, 0 },
755 { WM_CREATE, sent },
756 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
757 { WM_SIZE, sent|wparam, SIZE_RESTORED },
758 { WM_MOVE, sent },
759 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
760 { WM_GETMINMAXINFO, sent },
761 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
762 { WM_NCCALCSIZE, sent|wparam, 1 },
763 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
764 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
765 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
766 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
767 { 0 }
768 };
769 /* CreateWindow (for a child window, initially visible) */
770 static const struct message WmCreateVisibleChildSeq[] = {
771 { HCBT_CREATEWND, hook },
772 { WM_NCCREATE, sent },
773 /* child is inserted into parent's child list after WM_NCCREATE returns */
774 { WM_NCCALCSIZE, sent|wparam, 0 },
775 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
776 { WM_CREATE, sent },
777 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
778 { WM_SIZE, sent|wparam, SIZE_RESTORED },
779 { WM_MOVE, sent },
780 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
781 { WM_SHOWWINDOW, sent|wparam, 1 },
782 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
783 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
784 { WM_ERASEBKGND, sent|parent|optional },
785 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
786 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
787 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
788 { 0 }
789 };
790 /* ShowWindow(SW_SHOW) for a not visible child window */
791 static const struct message WmShowChildSeq[] = {
792 { WM_SHOWWINDOW, sent|wparam, 1 },
793 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
794 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
795 { WM_ERASEBKGND, sent|parent|optional },
796 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
797 { 0 }
798 };
799 /* ShowWindow(SW_HIDE) for a visible child window */
800 static const struct message WmHideChildSeq[] = {
801 { WM_SHOWWINDOW, sent|wparam, 0 },
802 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
803 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
804 { WM_ERASEBKGND, sent|parent|optional },
805 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
806 { 0 }
807 };
808 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
809 static const struct message WmHideChildSeq2[] = {
810 { WM_SHOWWINDOW, sent|wparam, 0 },
811 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
812 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
813 { WM_ERASEBKGND, sent|parent },
814 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
815 { 0 }
816 };
817 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
818 * for a not visible child window
819 */
820 static const struct message WmShowChildSeq_2[] = {
821 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
822 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
823 { WM_CHILDACTIVATE, sent },
824 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
825 { 0 }
826 };
827 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
828 * for a not visible child window
829 */
830 static const struct message WmShowChildSeq_3[] = {
831 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
832 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
833 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
834 { 0 }
835 };
836 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
837 * for a visible child window with a caption
838 */
839 static const struct message WmShowChildSeq_4[] = {
840 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
841 { WM_CHILDACTIVATE, sent },
842 { 0 }
843 };
844 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
845 static const struct message WmShowChildInvisibleParentSeq_1[] = {
846 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
847 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
848 { WM_NCCALCSIZE, sent|wparam, 1 },
849 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
850 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
851 { WM_MOVE, sent|defwinproc },
852 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
853 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
854 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
855 /* FIXME: Wine creates an icon/title window while Windows doesn't */
856 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
857 { WM_GETTEXT, sent|optional },
858 { 0 }
859 };
860 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
861 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
862 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
863 { 0 }
864 };
865 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
866 static const struct message WmShowChildInvisibleParentSeq_2[] = {
867 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
868 { WM_GETMINMAXINFO, sent },
869 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
870 { WM_NCCALCSIZE, sent|wparam, 1 },
871 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
872 { WM_CHILDACTIVATE, sent },
873 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
874 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
875 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
876 { 0 }
877 };
878 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
879 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
880 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
881 { 0 }
882 };
883 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
884 static const struct message WmShowChildInvisibleParentSeq_3[] = {
885 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
886 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
887 { WM_NCCALCSIZE, sent|wparam, 1 },
888 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
889 { WM_CHILDACTIVATE, sent },
890 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
891 { WM_MOVE, sent|defwinproc },
892 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
893 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
894 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
895 /* FIXME: Wine creates an icon/title window while Windows doesn't */
896 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
897 { WM_GETTEXT, sent|optional },
898 { 0 }
899 };
900 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
901 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
902 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
903 { 0 }
904 };
905 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
906 static const struct message WmShowChildInvisibleParentSeq_4[] = {
907 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
908 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
909 { WM_NCCALCSIZE, sent|wparam, 1 },
910 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
911 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
912 { WM_MOVE, sent|defwinproc },
913 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
914 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
915 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
916 /* FIXME: Wine creates an icon/title window while Windows doesn't */
917 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
918 { WM_GETTEXT, sent|optional },
919 { 0 }
920 };
921 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
922 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
923 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
924 { 0 }
925 };
926 /* ShowWindow(SW_SHOW) for child with invisible parent */
927 static const struct message WmShowChildInvisibleParentSeq_5[] = {
928 { WM_SHOWWINDOW, sent|wparam, 1 },
929 { 0 }
930 };
931 /* ShowWindow(SW_HIDE) for child with invisible parent */
932 static const struct message WmHideChildInvisibleParentSeq[] = {
933 { WM_SHOWWINDOW, sent|wparam, 0 },
934 { 0 }
935 };
936 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
937 static const struct message WmShowChildInvisibleParentSeq_6[] = {
938 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
939 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
940 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
941 { 0 }
942 };
943 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
944 static const struct message WmHideChildInvisibleParentSeq_2[] = {
945 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
946 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
947 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
948 { 0 }
949 };
950 /* DestroyWindow for a visible child window */
951 static const struct message WmDestroyChildSeq[] = {
952 { HCBT_DESTROYWND, hook },
953 { 0x0090, sent|optional },
954 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
955 { WM_SHOWWINDOW, sent|wparam, 0 },
956 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
957 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
958 { WM_ERASEBKGND, sent|parent|optional },
959 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
960 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
961 { WM_KILLFOCUS, sent },
962 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
963 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
964 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
965 { WM_SETFOCUS, sent|parent },
966 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
967 { WM_DESTROY, sent },
968 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
969 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
970 { WM_NCDESTROY, sent },
971 { 0 }
972 };
973 /* DestroyWindow for a visible child window with invisible parent */
974 static const struct message WmDestroyInvisibleChildSeq[] = {
975 { HCBT_DESTROYWND, hook },
976 { 0x0090, sent|optional },
977 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
978 { WM_SHOWWINDOW, sent|wparam, 0 },
979 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
980 { WM_DESTROY, sent },
981 { WM_NCDESTROY, sent },
982 { 0 }
983 };
984 /* Moving the mouse in nonclient area */
985 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
986 { WM_NCHITTEST, sent },
987 { WM_SETCURSOR, sent },
988 { WM_NCMOUSEMOVE, posted },
989 { 0 }
990 };
991 /* Moving the mouse in client area */
992 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
993 { WM_NCHITTEST, sent },
994 { WM_SETCURSOR, sent },
995 { WM_MOUSEMOVE, posted },
996 { 0 }
997 };
998 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
999 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1000 { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1001 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1002 { WM_GETMINMAXINFO, sent|defwinproc },
1003 { WM_ENTERSIZEMOVE, sent|defwinproc },
1004 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1005 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1006 { WM_MOVE, sent|defwinproc },
1007 { WM_EXITSIZEMOVE, sent|defwinproc },
1008 { 0 }
1009 };
1010 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1011 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1012 { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1013 { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1014 { WM_GETMINMAXINFO, sent|defwinproc },
1015 { WM_ENTERSIZEMOVE, sent|defwinproc },
1016 { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1017 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1018 { WM_GETMINMAXINFO, sent|defwinproc },
1019 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1020 { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1021 { WM_GETTEXT, sent|defwinproc },
1022 { WM_ERASEBKGND, sent|defwinproc },
1023 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1024 { WM_MOVE, sent|defwinproc },
1025 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1026 { WM_EXITSIZEMOVE, sent|defwinproc },
1027 { 0 }
1028 };
1029 /* Resizing child window with MoveWindow (32) */
1030 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1031 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1032 { WM_NCCALCSIZE, sent|wparam, 1 },
1033 { WM_ERASEBKGND, sent|parent|optional },
1034 { WM_ERASEBKGND, sent|optional },
1035 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1036 { WM_MOVE, sent|defwinproc },
1037 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1038 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1039 { 0 }
1040 };
1041 /* Clicking on inactive button */
1042 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1043 { WM_NCHITTEST, sent },
1044 { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1045 { WM_MOUSEACTIVATE, sent },
1046 { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1047 { WM_SETCURSOR, sent },
1048 { WM_SETCURSOR, sent|parent|defwinproc },
1049 { WM_LBUTTONDOWN, posted },
1050 { WM_KILLFOCUS, posted|parent },
1051 { WM_SETFOCUS, posted },
1052 { WM_CTLCOLORBTN, posted|parent },
1053 { BM_SETSTATE, posted },
1054 { WM_CTLCOLORBTN, posted|parent },
1055 { WM_LBUTTONUP, posted },
1056 { BM_SETSTATE, posted },
1057 { WM_CTLCOLORBTN, posted|parent },
1058 { WM_COMMAND, posted|parent },
1059 { 0 }
1060 };
1061 /* Reparenting a button (16/32) */
1062 /* The last child (button) reparented gets topmost for its new parent. */
1063 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1064 { WM_SHOWWINDOW, sent|wparam, 0 },
1065 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1066 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1067 { WM_ERASEBKGND, sent|parent },
1068 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1069 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1070 { WM_CHILDACTIVATE, sent },
1071 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1072 { WM_MOVE, sent|defwinproc },
1073 { WM_SHOWWINDOW, sent|wparam, 1 },
1074 { 0 }
1075 };
1076 /* Creation of a custom dialog (32) */
1077 static const struct message WmCreateCustomDialogSeq[] = {
1078 { HCBT_CREATEWND, hook },
1079 { WM_GETMINMAXINFO, sent },
1080 { WM_NCCREATE, sent },
1081 { WM_NCCALCSIZE, sent|wparam, 0 },
1082 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1083 { WM_CREATE, sent },
1084 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1085 { WM_SHOWWINDOW, sent|wparam, 1 },
1086 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1087 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1088 { HCBT_ACTIVATE, hook },
1089 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1090
1091
1092 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1093
1094 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1095
1096 { WM_NCACTIVATE, sent|wparam, 1 },
1097 { WM_GETTEXT, sent|optional|defwinproc },
1098 { WM_GETTEXT, sent|optional|defwinproc },
1099 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1100 { WM_ACTIVATE, sent|wparam, 1 },
1101 { WM_KILLFOCUS, sent|parent },
1102 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1103 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1104 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1105 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1106 { WM_SETFOCUS, sent },
1107 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1108 { WM_NCPAINT, sent|wparam, 1 },
1109 { WM_GETTEXT, sent|optional|defwinproc },
1110 { WM_GETTEXT, sent|optional|defwinproc },
1111 { WM_ERASEBKGND, sent },
1112 { WM_CTLCOLORDLG, sent|defwinproc },
1113 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1114 { WM_GETTEXT, sent|optional },
1115 { WM_GETTEXT, sent|optional },
1116 { WM_NCCALCSIZE, sent|optional },
1117 { WM_NCPAINT, sent|optional },
1118 { WM_GETTEXT, sent|optional|defwinproc },
1119 { WM_GETTEXT, sent|optional|defwinproc },
1120 { WM_ERASEBKGND, sent|optional },
1121 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1122 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1123 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1124 { WM_MOVE, sent },
1125 { 0 }
1126 };
1127 /* Calling EndDialog for a custom dialog (32) */
1128 static const struct message WmEndCustomDialogSeq[] = {
1129 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1130 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1131 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1132 { WM_GETTEXT, sent|optional },
1133 { HCBT_ACTIVATE, hook },
1134 { WM_NCACTIVATE, sent|wparam, 0 },
1135 { WM_GETTEXT, sent|optional|defwinproc },
1136 { WM_GETTEXT, sent|optional|defwinproc },
1137 { WM_ACTIVATE, sent|wparam, 0 },
1138 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1139 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1140 { HCBT_SETFOCUS, hook },
1141 { WM_KILLFOCUS, sent },
1142 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1143 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1144 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1145 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1146 { WM_SETFOCUS, sent|parent|defwinproc },
1147 { 0 }
1148 };
1149 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1150 static const struct message WmShowCustomDialogSeq[] = {
1151 { WM_SHOWWINDOW, sent|wparam, 1 },
1152 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1153 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1154 { HCBT_ACTIVATE, hook },
1155 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1156
1157 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1158
1159 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1160 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1161 { WM_NCACTIVATE, sent|wparam, 1 },
1162 { WM_ACTIVATE, sent|wparam, 1 },
1163
1164 { WM_KILLFOCUS, sent|parent },
1165 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1166 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1167 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1168 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1169 { WM_SETFOCUS, sent },
1170 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1171 { WM_NCPAINT, sent|wparam, 1 },
1172 { WM_ERASEBKGND, sent },
1173 { WM_CTLCOLORDLG, sent|defwinproc },
1174 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1175 { 0 }
1176 };
1177 /* Creation and destruction of a modal dialog (32) */
1178 static const struct message WmModalDialogSeq[] = {
1179 { WM_CANCELMODE, sent|parent },
1180 { HCBT_SETFOCUS, hook },
1181 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1182 { WM_KILLFOCUS, sent|parent },
1183 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1184 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1185 { WM_ENABLE, sent|parent|wparam, 0 },
1186 { HCBT_CREATEWND, hook },
1187 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1188 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1189 { WM_SETFONT, sent },
1190 { WM_INITDIALOG, sent },
1191 { WM_CHANGEUISTATE, sent|optional },
1192 { WM_UPDATEUISTATE, sent|optional },
1193 { WM_SHOWWINDOW, sent },
1194 { HCBT_ACTIVATE, hook },
1195 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1196 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1197 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1198 { WM_NCACTIVATE, sent|wparam, 1 },
1199 { WM_GETTEXT, sent|optional },
1200 { WM_ACTIVATE, sent|wparam, 1 },
1201 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1202 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1203 { WM_NCPAINT, sent },
1204 { WM_GETTEXT, sent|optional },
1205 { WM_ERASEBKGND, sent },
1206 { WM_CTLCOLORDLG, sent },
1207 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1208 { WM_GETTEXT, sent|optional },
1209 { WM_NCCALCSIZE, sent|optional },
1210 { WM_NCPAINT, sent|optional },
1211 { WM_GETTEXT, sent|optional },
1212 { WM_ERASEBKGND, sent|optional },
1213 { WM_CTLCOLORDLG, sent|optional },
1214 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1215 { WM_PAINT, sent|optional },
1216 { WM_CTLCOLORBTN, sent },
1217 { WM_ENTERIDLE, sent|parent|optional },
1218 { WM_ENTERIDLE, sent|parent|optional },
1219 { WM_ENTERIDLE, sent|parent|optional },
1220 { WM_ENTERIDLE, sent|parent|optional },
1221 { WM_ENTERIDLE, sent|parent|optional },
1222 { WM_ENTERIDLE, sent|parent|optional },
1223 { WM_ENTERIDLE, sent|parent|optional },
1224 { WM_ENTERIDLE, sent|parent|optional },
1225 { WM_ENTERIDLE, sent|parent|optional },
1226 { WM_ENTERIDLE, sent|parent|optional },
1227 { WM_ENTERIDLE, sent|parent|optional },
1228 { WM_ENTERIDLE, sent|parent|optional },
1229 { WM_ENTERIDLE, sent|parent|optional },
1230 { WM_ENTERIDLE, sent|parent|optional },
1231 { WM_ENTERIDLE, sent|parent|optional },
1232 { WM_ENTERIDLE, sent|parent|optional },
1233 { WM_ENTERIDLE, sent|parent|optional },
1234 { WM_ENTERIDLE, sent|parent|optional },
1235 { WM_ENTERIDLE, sent|parent|optional },
1236 { WM_ENTERIDLE, sent|parent|optional },
1237 { WM_TIMER, sent },
1238 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1239 { WM_ENABLE, sent|parent|wparam, 1 },
1240 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1241 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1242 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1243 { WM_GETTEXT, sent|optional },
1244 { HCBT_ACTIVATE, hook },
1245 { WM_NCACTIVATE, sent|wparam, 0 },
1246 { WM_GETTEXT, sent|optional },
1247 { WM_ACTIVATE, sent|wparam, 0 },
1248 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1249 { WM_WINDOWPOSCHANGING, sent|optional },
1250 { HCBT_SETFOCUS, hook },
1251 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1252 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1253 { WM_SETFOCUS, sent|parent|defwinproc },
1254 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1255 { HCBT_DESTROYWND, hook },
1256 { 0x0090, sent|optional },
1257 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1258 { WM_DESTROY, sent },
1259 { WM_NCDESTROY, sent },
1260 { 0 }
1261 };
1262 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1263 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1264 /* (inside dialog proc, handling WM_INITDIALOG) */
1265 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1266 { WM_NCCALCSIZE, sent },
1267 { WM_NCACTIVATE, sent|parent|wparam, 0 },
1268 { WM_GETTEXT, sent|defwinproc },
1269 { WM_ACTIVATE, sent|parent|wparam, 0 },
1270 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1271 { WM_WINDOWPOSCHANGING, sent|parent },
1272 { WM_NCACTIVATE, sent|wparam, 1 },
1273 { WM_ACTIVATE, sent|wparam, 1 },
1274 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1275 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1276 /* (setting focus) */
1277 { WM_SHOWWINDOW, sent|wparam, 1 },
1278 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1279 { WM_NCPAINT, sent },
1280 { WM_GETTEXT, sent|defwinproc },
1281 { WM_ERASEBKGND, sent },
1282 { WM_CTLCOLORDLG, sent|defwinproc },
1283 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1284 { WM_PAINT, sent },
1285 /* (bunch of WM_CTLCOLOR* for each control) */
1286 { WM_PAINT, sent|parent },
1287 { WM_ENTERIDLE, sent|parent|wparam, 0 },
1288 { WM_SETCURSOR, sent|parent },
1289 { 0 }
1290 };
1291 /* SetMenu for NonVisible windows with size change*/
1292 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1293 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1294 { WM_NCCALCSIZE, sent|wparam, 1 },
1295 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1296 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1297 { WM_MOVE, sent|defwinproc },
1298 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1299 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1300 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1301 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1302 { WM_GETTEXT, sent|optional },
1303 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1304 { 0 }
1305 };
1306 /* SetMenu for NonVisible windows with no size change */
1307 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1308 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1309 { WM_NCCALCSIZE, sent|wparam, 1 },
1310 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1311 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1312 { 0 }
1313 };
1314 /* SetMenu for Visible windows with size change */
1315 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1316 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1317 { WM_NCCALCSIZE, sent|wparam, 1 },
1318 { 0x0093, sent|defwinproc|optional },
1319 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1320 { WM_NCPAINT, sent }, /* wparam != 1 */
1321 { 0x0093, sent|defwinproc|optional },
1322 { 0x0093, sent|defwinproc|optional },
1323 { 0x0091, sent|defwinproc|optional },
1324 { 0x0092, sent|defwinproc|optional },
1325 { WM_GETTEXT, sent|defwinproc|optional },
1326 { WM_ERASEBKGND, sent|optional },
1327 { WM_ACTIVATE, sent|optional },
1328 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1329 { WM_MOVE, sent|defwinproc },
1330 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1331 { 0x0093, sent|optional },
1332 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1333 { 0x0093, sent|defwinproc|optional },
1334 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1335 { 0x0093, sent|defwinproc|optional },
1336 { 0x0093, sent|defwinproc|optional },
1337 { 0x0091, sent|defwinproc|optional },
1338 { 0x0092, sent|defwinproc|optional },
1339 { WM_ERASEBKGND, sent|optional },
1340 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1341 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1342 { 0 }
1343 };
1344 /* SetMenu for Visible windows with no size change */
1345 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1346 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1347 { WM_NCCALCSIZE, sent|wparam, 1 },
1348 { WM_NCPAINT, sent }, /* wparam != 1 */
1349 { WM_GETTEXT, sent|defwinproc|optional },
1350 { WM_ERASEBKGND, sent|optional },
1351 { WM_ACTIVATE, sent|optional },
1352 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1353 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1354 { 0 }
1355 };
1356 /* DrawMenuBar for a visible window */
1357 static const struct message WmDrawMenuBarSeq[] =
1358 {
1359 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1360 { WM_NCCALCSIZE, sent|wparam, 1 },
1361 { 0x0093, sent|defwinproc|optional },
1362 { WM_NCPAINT, sent }, /* wparam != 1 */
1363 { 0x0093, sent|defwinproc|optional },
1364 { 0x0093, sent|defwinproc|optional },
1365 { 0x0091, sent|defwinproc|optional },
1366 { 0x0092, sent|defwinproc|optional },
1367 { WM_GETTEXT, sent|defwinproc|optional },
1368 { WM_ERASEBKGND, sent|optional },
1369 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1370 { 0x0093, sent|optional },
1371 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1372 { 0 }
1373 };
1374
1375 static const struct message WmSetRedrawFalseSeq[] =
1376 {
1377 { WM_SETREDRAW, sent|wparam, 0 },
1378 { 0 }
1379 };
1380
1381 static const struct message WmSetRedrawTrueSeq[] =
1382 {
1383 { WM_SETREDRAW, sent|wparam, 1 },
1384 { 0 }
1385 };
1386
1387 static const struct message WmEnableWindowSeq_1[] =
1388 {
1389 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1390 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1391 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1392 { 0 }
1393 };
1394
1395 static const struct message WmEnableWindowSeq_2[] =
1396 {
1397 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1398 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1399 { 0 }
1400 };
1401
1402 static const struct message WmGetScrollRangeSeq[] =
1403 {
1404 { SBM_GETRANGE, sent },
1405 { 0 }
1406 };
1407 static const struct message WmGetScrollInfoSeq[] =
1408 {
1409 { SBM_GETSCROLLINFO, sent },
1410 { 0 }
1411 };
1412 static const struct message WmSetScrollRangeSeq[] =
1413 {
1414 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1415 sends SBM_SETSCROLLINFO.
1416 */
1417 { SBM_SETSCROLLINFO, sent },
1418 { 0 }
1419 };
1420 /* SetScrollRange for a window without a non-client area */
1421 static const struct message WmSetScrollRangeHSeq_empty[] =
1422 {
1423 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1424 { 0 }
1425 };
1426 static const struct message WmSetScrollRangeVSeq_empty[] =
1427 {
1428 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1429 { 0 }
1430 };
1431 static const struct message WmSetScrollRangeHVSeq[] =
1432 {
1433 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1434 { WM_NCCALCSIZE, sent|wparam, 1 },
1435 { WM_GETTEXT, sent|defwinproc|optional },
1436 { WM_ERASEBKGND, sent|optional },
1437 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1438 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1439 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1440 { 0 }
1441 };
1442 /* SetScrollRange for a window with a non-client area */
1443 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1444 {
1445 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1446 { WM_NCCALCSIZE, sent|wparam, 1 },
1447 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1448 { WM_NCPAINT, sent|optional },
1449 { WM_STYLECHANGING, sent|defwinproc|optional },
1450 { WM_STYLECHANGED, sent|defwinproc|optional },
1451 { WM_STYLECHANGING, sent|defwinproc|optional },
1452 { WM_STYLECHANGED, sent|defwinproc|optional },
1453 { WM_STYLECHANGING, sent|defwinproc|optional },
1454 { WM_STYLECHANGED, sent|defwinproc|optional },
1455 { WM_STYLECHANGING, sent|defwinproc|optional },
1456 { WM_STYLECHANGED, sent|defwinproc|optional },
1457 { WM_GETTEXT, sent|defwinproc|optional },
1458 { WM_GETTEXT, sent|defwinproc|optional },
1459 { WM_ERASEBKGND, sent|optional },
1460 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1461 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1462 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1463 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1464 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1465 { WM_GETTEXT, sent|optional },
1466 { WM_GETTEXT, sent|optional },
1467 { WM_GETTEXT, sent|optional },
1468 { WM_GETTEXT, sent|optional },
1469 { 0 }
1470 };
1471 /* test if we receive the right sequence of messages */
1472 /* after calling ShowWindow( SW_SHOWNA) */
1473 static const struct message WmSHOWNAChildInvisParInvis[] = {
1474 { WM_SHOWWINDOW, sent|wparam, 1 },
1475 { 0 }
1476 };
1477 static const struct message WmSHOWNAChildVisParInvis[] = {
1478 { WM_SHOWWINDOW, sent|wparam, 1 },
1479 { 0 }
1480 };
1481 static const struct message WmSHOWNAChildVisParVis[] = {
1482 { WM_SHOWWINDOW, sent|wparam, 1 },
1483 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1484 { 0 }
1485 };
1486 static const struct message WmSHOWNAChildInvisParVis[] = {
1487 { WM_SHOWWINDOW, sent|wparam, 1 },
1488 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1489 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1490 { WM_ERASEBKGND, sent|optional },
1491 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1492 { 0 }
1493 };
1494 static const struct message WmSHOWNATopVisible[] = {
1495 { WM_SHOWWINDOW, sent|wparam, 1 },
1496 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1497 { 0 }
1498 };
1499 static const struct message WmSHOWNATopInvisible[] = {
1500 { WM_SHOWWINDOW, sent|wparam, 1 },
1501 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1502 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1503 { WM_NCPAINT, sent|wparam, 1 },
1504 { WM_GETTEXT, sent|defwinproc|optional },
1505 { WM_ERASEBKGND, sent|optional },
1506 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1507 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1508 { WM_NCPAINT, sent|wparam|optional, 1 },
1509 { WM_ERASEBKGND, sent|optional },
1510 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1511 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1512 { WM_MOVE, sent },
1513 { 0 }
1514 };
1515
1516 static int after_end_dialog, test_def_id;
1517 static int sequence_cnt, sequence_size;
1518 static struct message* sequence;
1519 static int log_all_parent_messages;
1520
1521 /* user32 functions */
1522 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1523 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1524 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1525 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1526 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1527 /* kernel32 functions */
1528 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1529
1530 static void init_procs(void)
1531 {
1532 HMODULE user32 = GetModuleHandleA("user32.dll");
1533 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1534
1535 #define GET_PROC(dll, func) \
1536 p ## func = (void*)GetProcAddress(dll, #func); \
1537 if(!p ## func) { \
1538 trace("GetProcAddress(%s) failed\n", #func); \
1539 }
1540
1541 GET_PROC(user32, GetAncestor)
1542 GET_PROC(user32, NotifyWinEvent)
1543 GET_PROC(user32, SetWinEventHook)
1544 GET_PROC(user32, TrackMouseEvent)
1545 GET_PROC(user32, UnhookWinEvent)
1546
1547 GET_PROC(kernel32, GetCPInfoExA)
1548
1549 #undef GET_PROC
1550 }
1551
1552 static void add_message(const struct message *msg)
1553 {
1554 if (!sequence)
1555 {
1556 sequence_size = 10;
1557 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1558 }
1559 if (sequence_cnt == sequence_size)
1560 {
1561 sequence_size *= 2;
1562 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1563 }
1564 assert(sequence);
1565
1566 sequence[sequence_cnt].message = msg->message;
1567 sequence[sequence_cnt].flags = msg->flags;
1568 sequence[sequence_cnt].wParam = msg->wParam;
1569 sequence[sequence_cnt].lParam = msg->lParam;
1570
1571 sequence_cnt++;
1572 }
1573
1574 /* try to make sure pending X events have been processed before continuing */
1575 static void flush_events(void)
1576 {
1577 MSG msg;
1578 int diff = 200;
1579 int min_timeout = 50;
1580 DWORD time = GetTickCount() + diff;
1581
1582 while (diff > 0)
1583 {
1584 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1585 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1586 diff = time - GetTickCount();
1587 min_timeout = 10;
1588 }
1589 }
1590
1591 static void flush_sequence(void)
1592 {
1593 HeapFree(GetProcessHeap(), 0, sequence);
1594 sequence = 0;
1595 sequence_cnt = sequence_size = 0;
1596 }
1597
1598 #define ok_sequence( exp, contx, todo) \
1599 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1600
1601
1602 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1603 const char *file, int line)
1604 {
1605 static const struct message end_of_sequence = { 0, 0, 0, 0 };
1606 const struct message *actual;
1607 int failcount = 0;
1608
1609 add_message(&end_of_sequence);
1610
1611 actual = sequence;
1612
1613 while (expected->message && actual->message)
1614 {
1615 trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1616
1617 if (expected->message == actual->message)
1618 {
1619 if (expected->flags & wparam)
1620 {
1621 if (expected->wParam != actual->wParam && todo)
1622 {
1623 todo_wine {
1624 failcount ++;
1625 ok_( file, line) (FALSE,
1626 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1627 context, expected->message, expected->wParam, actual->wParam);
1628 }
1629 }
1630 else
1631 ok_( file, line) (expected->wParam == actual->wParam,
1632 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1633 context, expected->message, expected->wParam, actual->wParam);
1634 }
1635 if (expected->flags & lparam)
1636 {
1637 if (expected->lParam != actual->lParam && todo)
1638 {
1639 todo_wine {
1640 failcount ++;
1641 ok_( file, line) (FALSE,
1642 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1643 context, expected->message, expected->lParam, actual->lParam);
1644 }
1645 }
1646 else
1647 ok_( file, line) (expected->lParam == actual->lParam,
1648 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1649 context, expected->message, expected->lParam, actual->lParam);
1650 }
1651 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1652 {
1653 todo_wine {
1654 failcount ++;
1655 ok_( file, line) (FALSE,
1656 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1657 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1658 }
1659 }
1660 else
1661 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1662 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1663 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1664 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1665 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1666 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1667 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1668 "%s: the msg 0x%04x should have been %s\n",
1669 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1670 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1671 "%s: the msg 0x%04x was expected in %s\n",
1672 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1673 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1674 "%s: the msg 0x%04x should have been sent by a hook\n",
1675 context, expected->message);
1676 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1677 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1678 context, expected->message);
1679 expected++;
1680 actual++;
1681 }
1682 /* silently drop winevent messages if there is no support for them */
1683 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1684 expected++;
1685 else if (todo)
1686 {
1687 failcount++;
1688 todo_wine {
1689 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1690 context, expected->message, actual->message);
1691 }
1692 flush_sequence();
1693 return;
1694 }
1695 else
1696 {
1697 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1698 context, expected->message, actual->message);
1699 expected++;
1700 actual++;
1701 }
1702 }
1703
1704 /* skip all optional trailing messages */
1705 while (expected->message && ((expected->flags & optional) ||
1706 ((expected->flags & winevent_hook) && !hEvent_hook)))
1707 expected++;
1708
1709 if (todo)
1710 {
1711 todo_wine {
1712 if (expected->message || actual->message) {
1713 failcount++;
1714 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1715 context, expected->message, actual->message);
1716 }
1717 }
1718 }
1719 else
1720 {
1721 if (expected->message || actual->message)
1722 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1723 context, expected->message, actual->message);
1724 }
1725 if( todo && !failcount) /* succeeded yet marked todo */
1726 todo_wine {
1727 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1728 }
1729
1730 flush_sequence();
1731 }
1732
1733 /******************************** MDI test **********************************/
1734
1735 /* CreateWindow for MDI frame window, initially visible */
1736 static const struct message WmCreateMDIframeSeq[] = {
1737 { HCBT_CREATEWND, hook },
1738 { WM_GETMINMAXINFO, sent },
1739 { WM_NCCREATE, sent },
1740 { WM_NCCALCSIZE, sent|wparam, 0 },
1741 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1742 { WM_CREATE, sent },
1743 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1744 { WM_SHOWWINDOW, sent|wparam, 1 },
1745 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1746 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1747 { HCBT_ACTIVATE, hook },
1748 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1749 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1750 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1751 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1752 { WM_NCACTIVATE, sent|wparam, 1 },
1753 { WM_GETTEXT, sent|defwinproc|optional },
1754 { WM_ACTIVATE, sent|wparam, 1 },
1755 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1756 { HCBT_SETFOCUS, hook },
1757 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1758 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1759 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1760 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1761 /* Win9x adds SWP_NOZORDER below */
1762 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1763 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1764 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1765 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1766 { WM_MOVE, sent },
1767 { 0 }
1768 };
1769 /* DestroyWindow for MDI frame window, initially visible */
1770 static const struct message WmDestroyMDIframeSeq[] = {
1771 { HCBT_DESTROYWND, hook },
1772 { 0x0090, sent|optional },
1773 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1774 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1775 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1776 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1777 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1778 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1779 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1780 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1781 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1782 { WM_DESTROY, sent },
1783 { WM_NCDESTROY, sent },
1784 { 0 }
1785 };
1786 /* CreateWindow for MDI client window, initially visible */
1787 static const struct message WmCreateMDIclientSeq[] = {
1788 { HCBT_CREATEWND, hook },
1789 { WM_NCCREATE, sent },
1790 { WM_NCCALCSIZE, sent|wparam, 0 },
1791 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1792 { WM_CREATE, sent },
1793 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1794 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1795 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1796 { WM_MOVE, sent },
1797 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1798 { WM_SHOWWINDOW, sent|wparam, 1 },
1799 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1800 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1801 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1802 { 0 }
1803 };
1804 /* ShowWindow(SW_SHOW) for MDI client window */
1805 static const struct message WmShowMDIclientSeq[] = {
1806 { WM_SHOWWINDOW, sent|wparam, 1 },
1807 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1808 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1809 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1810 { 0 }
1811 };
1812 /* ShowWindow(SW_HIDE) for MDI client window */
1813 static const struct message WmHideMDIclientSeq[] = {
1814 { WM_SHOWWINDOW, sent|wparam, 0 },
1815 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1816 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1817 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1818 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1819 { 0 }
1820 };
1821 /* DestroyWindow for MDI client window, initially visible */
1822 static const struct message WmDestroyMDIclientSeq[] = {
1823 { HCBT_DESTROYWND, hook },
1824 { 0x0090, sent|optional },
1825 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1826 { WM_SHOWWINDOW, sent|wparam, 0 },
1827 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1828 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1829 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1830 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1831 { WM_DESTROY, sent },
1832 { WM_NCDESTROY, sent },
1833 { 0 }
1834 };
1835 /* CreateWindow for MDI child window, initially visible */
1836 static const struct message WmCreateMDIchildVisibleSeq[] = {
1837 { HCBT_CREATEWND, hook },
1838 { WM_NCCREATE, sent },
1839 { WM_NCCALCSIZE, sent|wparam, 0 },
1840 { WM_CREATE, sent },
1841 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1842 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1843 { WM_MOVE, sent },
1844 /* Win2k sends wparam set to
1845 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1846 * while Win9x doesn't bother to set child window id according to
1847 * CLIENTCREATESTRUCT.idFirstChild
1848 */
1849 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1850 { WM_SHOWWINDOW, sent|wparam, 1 },
1851 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1852 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1853 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1854 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1855 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1856 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1857 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1858
1859 /* Win9x: message sequence terminates here. */
1860
1861 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1862 { HCBT_SETFOCUS, hook }, /* in MDI client */
1863 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1864 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1865 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1866 { WM_SETFOCUS, sent }, /* in MDI client */
1867 { HCBT_SETFOCUS, hook },
1868 { WM_KILLFOCUS, sent }, /* in MDI client */
1869 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1870 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1871 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1872 { WM_SETFOCUS, sent|defwinproc },
1873 { WM_MDIACTIVATE, sent|defwinproc },
1874 { 0 }
1875 };
1876 /* CreateWindow for MDI child window with invisible parent */
1877 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
1878 { HCBT_CREATEWND, hook },
1879 { WM_GETMINMAXINFO, sent },
1880 { WM_NCCREATE, sent },
1881 { WM_NCCALCSIZE, sent|wparam, 0 },
1882 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1883 { WM_CREATE, sent },
1884 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1885 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1886 { WM_MOVE, sent },
1887 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1888 { WM_SHOWWINDOW, sent|wparam, 1 },
1889 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1890 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1891 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1892 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1893
1894 /* Win9x: message sequence terminates here. */
1895
1896 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1897 { HCBT_SETFOCUS, hook }, /* in MDI client */
1898 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1899 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1900 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1901 { WM_SETFOCUS, sent }, /* in MDI client */
1902 { HCBT_SETFOCUS, hook },
1903 { WM_KILLFOCUS, sent }, /* in MDI client */
1904 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1905 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1906 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1907 { WM_SETFOCUS, sent|defwinproc },
1908 { WM_MDIACTIVATE, sent|defwinproc },
1909 { 0 }
1910 };
1911 /* DestroyWindow for MDI child window, initially visible */
1912 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1913 { HCBT_DESTROYWND, hook },
1914 /* Win2k sends wparam set to
1915 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1916 * while Win9x doesn't bother to set child window id according to
1917 * CLIENTCREATESTRUCT.idFirstChild
1918 */
1919 { 0x0090, sent|optional },
1920 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1921 { WM_SHOWWINDOW, sent|wparam, 0 },
1922 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1923 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1924 { WM_ERASEBKGND, sent|parent|optional },
1925 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1926
1927 /* { WM_DESTROY, sent }
1928 * Win9x: message sequence terminates here.
1929 */
1930
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 */
1937
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 */
1944
1945 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1946
1947 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1948 { WM_KILLFOCUS, sent },
1949 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1950 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1951 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1952 { WM_SETFOCUS, sent }, /* in MDI client */
1953
1954 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1955 { WM_KILLFOCUS, sent }, /* in MDI client */
1956 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1957 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1958 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1959 { WM_SETFOCUS, sent }, /* in MDI client */
1960
1961 { WM_DESTROY, sent },
1962
1963 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1964 { WM_KILLFOCUS, sent },
1965 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1966 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1967 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1968 { WM_SETFOCUS, sent }, /* in MDI client */
1969
1970 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1971 { WM_KILLFOCUS, sent }, /* in MDI client */
1972 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1973 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1974 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1975 { WM_SETFOCUS, sent }, /* in MDI client */
1976
1977 { WM_NCDESTROY, sent },
1978 { 0 }
1979 };
1980 /* CreateWindow for MDI child window, initially invisible */
1981 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1982 { HCBT_CREATEWND, hook },
1983 { WM_NCCREATE, sent },
1984 { WM_NCCALCSIZE, sent|wparam, 0 },
1985 { WM_CREATE, sent },
1986 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1987 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1988 { WM_MOVE, sent },
1989 /* Win2k sends wparam set to
1990 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1991 * while Win9x doesn't bother to set child window id according to
1992 * CLIENTCREATESTRUCT.idFirstChild
1993 */
1994 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1995 { 0 }
1996 };
1997 /* DestroyWindow for MDI child window, initially invisible */
1998 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1999 { HCBT_DESTROYWND, hook },
2000 /* Win2k sends wparam set to
2001 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2002 * while Win9x doesn't bother to set child window id according to
2003 * CLIENTCREATESTRUCT.idFirstChild
2004 */
2005 { 0x0090, sent|optional },
2006 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2007 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2008 { WM_DESTROY, sent },
2009 { WM_NCDESTROY, sent },
2010 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2011 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2012 { 0 }
2013 };
2014 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2015 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2016 { HCBT_CREATEWND, hook },
2017 { WM_NCCREATE, sent },
2018 { WM_NCCALCSIZE, sent|wparam, 0 },
2019 { WM_CREATE, sent },
2020 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2021 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2022 { WM_MOVE, sent },
2023 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2024 { WM_GETMINMAXINFO, sent },
2025 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2026 { WM_NCCALCSIZE, sent|wparam, 1 },
2027 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2028 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2029 /* in MDI frame */
2030 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2031 { WM_NCCALCSIZE, sent|wparam, 1 },
2032 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2033 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2034 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2035 /* Win2k sends wparam set to
2036 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2037 * while Win9x doesn't bother to set child window id according to
2038 * CLIENTCREATESTRUCT.idFirstChild
2039 */
2040 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2041 { WM_SHOWWINDOW, sent|wparam, 1 },
2042 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2043 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2044 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2045 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2046 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2047 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2048 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2049
2050 /* Win9x: message sequence terminates here. */
2051
2052 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2053 { HCBT_SETFOCUS, hook }, /* in MDI client */
2054 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2055 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2056 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2057 { WM_SETFOCUS, sent }, /* in MDI client */
2058 { HCBT_SETFOCUS, hook },
2059 { WM_KILLFOCUS, sent }, /* in MDI client */
2060 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2061 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2062 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2063 { WM_SETFOCUS, sent|defwinproc },
2064 { WM_MDIACTIVATE, sent|defwinproc },
2065 /* in MDI frame */
2066 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2067 { WM_NCCALCSIZE, sent|wparam, 1 },
2068 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2069 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2070 { 0 }
2071 };
2072 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2073 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2074 /* restore the 1st MDI child */
2075 { WM_SETREDRAW, sent|wparam, 0 },
2076 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2077 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2078 { WM_NCCALCSIZE, sent|wparam, 1 },
2079 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2080 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2081 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2082 /* in MDI frame */
2083 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2084 { WM_NCCALCSIZE, sent|wparam, 1 },
2085 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2086 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2087 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2088 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2089 /* create the 2nd MDI child */
2090 { HCBT_CREATEWND, hook },
2091 { WM_NCCREATE, sent },
2092 { WM_NCCALCSIZE, sent|wparam, 0 },
2093 { WM_CREATE, sent },
2094 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2095 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2096 { WM_MOVE, sent },
2097 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2098 { WM_GETMINMAXINFO, sent },
2099 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2100 { WM_NCCALCSIZE, sent|wparam, 1 },
2101 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2102 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2103 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2104 /* in MDI frame */
2105 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2106 { WM_NCCALCSIZE, sent|wparam, 1 },
2107 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2108 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2109 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2110 /* Win2k sends wparam set to
2111 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2112 * while Win9x doesn't bother to set child window id according to
2113 * CLIENTCREATESTRUCT.idFirstChild
2114 */
2115 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2116 { WM_SHOWWINDOW, sent|wparam, 1 },
2117 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2118 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2119 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2120 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2121 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2122 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2123
2124 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2125 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2126
2127 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2128
2129 /* Win9x: message sequence terminates here. */
2130
2131 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2132 { HCBT_SETFOCUS, hook },
2133 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
2134 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2135 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2136 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2137 { WM_SETFOCUS, sent }, /* in MDI client */
2138 { HCBT_SETFOCUS, hook },
2139 { WM_KILLFOCUS, sent }, /* in MDI client */
2140 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2141 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2142 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2143 { WM_SETFOCUS, sent|defwinproc },
2144
2145 { WM_MDIACTIVATE, sent|defwinproc },
2146 /* in MDI frame */
2147 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2148 { WM_NCCALCSIZE, sent|wparam, 1 },
2149 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2150 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2151 { 0 }
2152 };
2153 /* WM_MDICREATE MDI child window, initially visible and maximized */
2154 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2155 { WM_MDICREATE, sent },
2156 { HCBT_CREATEWND, hook },
2157 { WM_NCCREATE, sent },
2158 { WM_NCCALCSIZE, sent|wparam, 0 },
2159 { WM_CREATE, sent },
2160 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2161 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2162 { WM_MOVE, sent },
2163 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2164 { WM_GETMINMAXINFO, sent },
2165 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2166 { WM_NCCALCSIZE, sent|wparam, 1 },
2167 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2168 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2169
2170 /* in MDI frame */
2171 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2172 { WM_NCCALCSIZE, sent|wparam, 1 },
2173 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2174 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2175 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2176
2177 /* Win2k sends wparam set to
2178 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2179 * while Win9x doesn't bother to set child window id according to
2180 * CLIENTCREATESTRUCT.idFirstChild
2181 */
2182 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2183 { WM_SHOWWINDOW, sent|wparam, 1 },
2184 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2185
2186 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2187
2188 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2189 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2190 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2191
2192 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2193 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2194
2195 /* Win9x: message sequence terminates here. */
2196
2197 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2198 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2199 { HCBT_SETFOCUS, hook }, /* in MDI client */
2200 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2201 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2202 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2203 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2204 { HCBT_SETFOCUS, hook|optional },
2205 { WM_KILLFOCUS, sent }, /* in MDI client */
2206 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2207 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2208 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2209 { WM_SETFOCUS, sent|defwinproc },
2210
2211 { WM_MDIACTIVATE, sent|defwinproc },
2212
2213 /* in MDI child */
2214 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2215 { WM_NCCALCSIZE, sent|wparam, 1 },
2216 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2217 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2218
2219 /* in MDI frame */
2220 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2221 { WM_NCCALCSIZE, sent|wparam, 1 },
2222 { 0x0093, sent|defwinproc|optional },
2223 { 0x0093, sent|defwinproc|optional },
2224 { 0x0093, sent|defwinproc|optional },
2225 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2226 { WM_MOVE, sent|defwinproc },
2227 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2228
2229 /* in MDI client */
2230 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2231 { WM_NCCALCSIZE, sent|wparam, 1 },
2232 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2233 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2234
2235 /* in MDI child */
2236 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2237 { WM_NCCALCSIZE, sent|wparam, 1 },
2238 { 0x0093, sent|optional },
2239 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2240 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2241
2242 { 0x0093, sent|optional },
2243 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2244 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2245 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2246 { 0x0093, sent|defwinproc|optional },
2247 { 0x0093, sent|defwinproc|optional },
2248 { 0x0093, sent|defwinproc|optional },
2249 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2250 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2251
2252 { 0 }
2253 };
2254 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2255 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2256 { HCBT_CREATEWND, hook },
2257 { WM_GETMINMAXINFO, sent },
2258 { WM_NCCREATE, sent },
2259 { WM_NCCALCSIZE, sent|wparam, 0 },
2260 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2261 { WM_CREATE, sent },
2262 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2263 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2264 { WM_MOVE, sent },
2265 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2266 { WM_GETMINMAXINFO, sent },
2267 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2268 { WM_GETMINMAXINFO, sent|defwinproc },
2269 { WM_NCCALCSIZE, sent|wparam, 1 },
2270 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2271 { WM_MOVE, sent|defwinproc },
2272 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2273 /* in MDI frame */
2274 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2275 { WM_NCCALCSIZE, sent|wparam, 1 },
2276 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2277 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2278 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2279 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2280 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2281 /* Win2k sends wparam set to
2282 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2283 * while Win9x doesn't bother to set child window id according to
2284 * CLIENTCREATESTRUCT.idFirstChild
2285 */
2286 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2287 { 0 }
2288 };
2289 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2290 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2291 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2292 { HCBT_SYSCOMMAND, hook },
2293 { WM_CLOSE, sent|defwinproc },
2294 { WM_MDIDESTROY, sent }, /* in MDI client */
2295
2296 /* bring the 1st MDI child to top */
2297 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2298 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2299
2300 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2301
2302 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2303 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2304 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2305
2306 /* maximize the 1st MDI child */
2307 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2308 { WM_GETMINMAXINFO, sent|defwinproc },
2309 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2310 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2311 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2312 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2313 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2314
2315 /* restore the 2nd MDI child */
2316 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2317 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2318 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2319 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2320
2321 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2322
2323 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2324 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2325
2326 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2327
2328 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2329 /* in MDI frame */
2330 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2331 { WM_NCCALCSIZE, sent|wparam, 1 },
2332 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2333 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2334 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2335
2336 /* bring the 1st MDI child to top */
2337 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2338 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2339 { HCBT_SETFOCUS, hook },
2340 { WM_KILLFOCUS, sent|defwinproc },
2341 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2342 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2343 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2344 { WM_SETFOCUS, sent }, /* in MDI client */
2345 { HCBT_SETFOCUS, hook },
2346 { WM_KILLFOCUS, sent }, /* in MDI client */
2347 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2348 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2349 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2350 { WM_SETFOCUS, sent|defwinproc },
2351 { WM_MDIACTIVATE, sent|defwinproc },
2352 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2353
2354 /* apparently ShowWindow(SW_SHOW) on an MDI client */
2355 { WM_SHOWWINDOW, sent|wparam, 1 },
2356 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2357 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2358 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2359 { WM_MDIREFRESHMENU, sent },
2360
2361 { HCBT_DESTROYWND, hook },
2362 /* Win2k sends wparam set to
2363 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2364 * while Win9x doesn't bother to set child window id according to
2365 * CLIENTCREATESTRUCT.idFirstChild
2366 */
2367 { 0x0090, sent|defwinproc|optional },
2368 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2369 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2370 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2371 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2372 { WM_ERASEBKGND, sent|parent|optional },
2373 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2374
2375 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2376 { WM_DESTROY, sent|defwinproc },
2377 { WM_NCDESTROY, sent|defwinproc },
2378 { 0 }
2379 };
2380 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2381 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2382 { WM_MDIDESTROY, sent }, /* in MDI client */
2383 { WM_SHOWWINDOW, sent|wparam, 0 },
2384 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2385 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2386 { WM_ERASEBKGND, sent|parent|optional },
2387 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2388
2389 { HCBT_SETFOCUS, hook },
2390 { WM_KILLFOCUS, sent },
2391 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2392 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2393 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2394 { WM_SETFOCUS, sent }, /* in MDI client */
2395 { HCBT_SETFOCUS, hook },
2396 { WM_KILLFOCUS, sent }, /* in MDI client */
2397 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2398 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2399 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2400 { WM_SETFOCUS, sent },
2401
2402 /* in MDI child */
2403 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2404 { WM_NCCALCSIZE, sent|wparam, 1 },
2405 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2406 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2407
2408 /* in MDI frame */
2409 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2410 { WM_NCCALCSIZE, sent|wparam, 1 },
2411 { 0x0093, sent|defwinproc|optional },
2412 { 0x0093, sent|defwinproc|optional },
2413 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2414 { WM_MOVE, sent|defwinproc },
2415 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2416
2417 /* in MDI client */
2418 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2419 { WM_NCCALCSIZE, sent|wparam, 1 },
2420 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2421 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2422
2423 /* in MDI child */
2424 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2425 { WM_NCCALCSIZE, sent|wparam, 1 },
2426 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2427 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2428
2429 /* in MDI child */
2430 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2431 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2432 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2433 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2434
2435 /* in MDI frame */
2436 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2437 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2438 { 0x0093, sent|defwinproc|optional },
2439 { 0x0093, sent|defwinproc|optional },
2440 { 0x0093, sent|defwinproc|optional },
2441 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2442 { WM_MOVE, sent|defwinproc },
2443 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2444
2445 /* in MDI client */
2446 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2447 { WM_NCCALCSIZE, sent|wparam, 1 },
2448 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2449 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2450
2451 /* in MDI child */
2452 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2453 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2454 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2455 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2456 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2457 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2458
2459 { 0x0093, sent|defwinproc|optional },
2460 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2461 { 0x0093, sent|defwinproc|optional },
2462 { 0x0093, sent|defwinproc|optional },
2463 { 0x0093, sent|defwinproc|optional },
2464 { 0x0093, sent|optional },
2465
2466 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2467 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2468 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2469 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2470 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2471
2472 /* in MDI frame */
2473 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2474 { WM_NCCALCSIZE, sent|wparam, 1 },
2475 { 0x0093, sent|defwinproc|optional },
2476 { 0x0093, sent|defwinproc|optional },
2477 { 0x0093, sent|defwinproc|optional },
2478 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2479 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2480 { 0x0093, sent|optional },
2481
2482 { WM_NCACTIVATE, sent|wparam, 0 },
2483 { WM_MDIACTIVATE, sent },
2484
2485 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2486 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2487 { WM_NCCALCSIZE, sent|wparam, 1 },
2488
2489 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2490
2491 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2492 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2493 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2494
2495 /* in MDI child */
2496 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2497 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2498 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2499 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2500
2501 /* in MDI frame */
2502 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2503 { WM_NCCALCSIZE, sent|wparam, 1 },
2504 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2505 { WM_MOVE, sent|defwinproc },
2506 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2507
2508 /* in MDI client */
2509 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2510 { WM_NCCALCSIZE, sent|wparam, 1 },
2511 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2512 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2513 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2514 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2515 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2516 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2517 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2518
2519 { HCBT_SETFOCUS, hook },
2520 { WM_KILLFOCUS, sent },
2521 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2522 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2523 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2524 { WM_SETFOCUS, sent }, /* in MDI client */
2525
2526 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2527
2528 { HCBT_DESTROYWND, hook },
2529 /* Win2k sends wparam set to
2530 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2531 * while Win9x doesn't bother to set child window id according to
2532 * CLIENTCREATESTRUCT.idFirstChild
2533 */
2534 { 0x0090, sent|optional },
2535 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2536
2537 { WM_SHOWWINDOW, sent|wparam, 0 },
2538 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2539 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2540 { WM_ERASEBKGND, sent|parent|optional },
2541 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2542
2543 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2544 { WM_DESTROY, sent },
2545 { WM_NCDESTROY, sent },
2546 { 0 }
2547 };
2548 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2549 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2550 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2551 { WM_GETMINMAXINFO, sent },
2552 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
2553 { WM_NCCALCSIZE, sent|wparam, 1 },
2554 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2555 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2556
2557 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2558 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2559 { HCBT_SETFOCUS, hook },
2560 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2561 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2562 { WM_SETFOCUS, sent }, /* in MDI client */
2563 { HCBT_SETFOCUS, hook },
2564 { WM_KILLFOCUS, sent }, /* in MDI client */
2565 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2566 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2567 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2568 { WM_SETFOCUS, sent|defwinproc },
2569 { WM_MDIACTIVATE, sent|defwinproc },
2570 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2571 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2572 /* in MDI frame */
2573 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2574 { WM_NCCALCSIZE, sent|wparam, 1 },
2575 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2576 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2577 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2578 { 0 }
2579 };
2580 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2581 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2582 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2583 { WM_GETMINMAXINFO, sent },
2584 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2585 { WM_GETMINMAXINFO, sent|defwinproc },
2586 { WM_NCCALCSIZE, sent|wparam, 1 },
2587 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2588 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2589
2590 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2591 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2592 { HCBT_SETFOCUS, hook },
2593 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2594 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2595 { WM_SETFOCUS, sent }, /* in MDI client */
2596 { HCBT_SETFOCUS, hook },
2597 { WM_KILLFOCUS, sent }, /* in MDI client */
2598 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2599 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2600 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2601 { WM_SETFOCUS, sent|defwinproc },
2602 { WM_MDIACTIVATE, sent|defwinproc },
2603 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2604 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2605 { 0 }
2606 };
2607 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2608 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2609 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2610 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2611 { WM_GETMINMAXINFO, sent },
2612 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2613 { WM_GETMINMAXINFO, sent|defwinproc },
2614 { WM_NCCALCSIZE, sent|wparam, 1 },
2615 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2616 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2617 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
2618 { WM_MOVE, sent|defwinproc },
2619 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2620
2621 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2622 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2623 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2624 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2625 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2626 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2627 /* in MDI frame */
2628 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2629 { WM_NCCALCSIZE, sent|wparam, 1 },
2630 { 0x0093, sent|defwinproc|optional },
2631 { 0x0094, sent|defwinproc|optional },
2632 { 0x0094, sent|defwinproc|optional },
2633 { 0x0094, sent|defwinproc|optional },
2634 { 0x0094, sent|defwinproc|optional },
2635 { 0x0093, sent|defwinproc|optional },
2636 { 0x0093, sent|defwinproc|optional },
2637 { 0x0091, sent|defwinproc|optional },
2638 { 0x0092, sent|defwinproc|optional },
2639 { 0x0092, sent|defwinproc|optional },
2640 { 0x0092, sent|defwinproc|optional },
2641 { 0x0092, sent|defwinproc|optional },
2642 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2643 { WM_MOVE, sent|defwinproc },
2644 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2645 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2646 /* in MDI client */
2647 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2648 { WM_NCCALCSIZE, sent|wparam, 1 },
2649 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2650 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2651 /* in MDI child */
2652 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2653 { WM_GETMINMAXINFO, sent|defwinproc },
2654 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2655 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2656 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2657 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2658 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2659 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2660 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2661 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2662 /* in MDI frame */
2663 { 0x0093, sent|optional },
2664 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2665 { 0x0093, sent|defwinproc|optional },
2666 { 0x0093, sent|defwinproc|optional },
2667 { 0x0093, sent|defwinproc|optional },
2668 { 0x0091, sent|defwinproc|optional },
2669 { 0x0092, sent|defwinproc|optional },
2670 { 0x0092, sent|defwinproc|optional },
2671 { 0x0092, sent|defwinproc|optional },
2672 { 0x0092, sent|defwinproc|optional },
2673 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2674 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2675 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2676 { 0 }
2677 };
2678 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2679 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2680 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2681 { WM_GETMINMAXINFO, sent },
2682 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2683 { WM_NCCALCSIZE, sent|wparam, 1 },
2684 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2685 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2686 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2687 /* in MDI frame */
2688 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2689 { WM_NCCALCSIZE, sent|wparam, 1 },
2690 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2691 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2692 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2693 { 0 }
2694 };
2695 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2696 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2697 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2698 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2699 { WM_NCCALCSIZE, sent|wparam, 1 },
2700 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2701 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2702 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2703 /* in MDI frame */
2704 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2705 { WM_NCCALCSIZE, sent|wparam, 1 },
2706 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2707 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2708 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2709 { 0 }
2710 };
2711 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2712 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2713 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2714 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2715 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
2716 { WM_NCCALCSIZE, sent|wparam, 1 },
2717 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2718 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2719 { WM_MOVE, sent|defwinproc },
2720 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2721 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2722 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2723 { HCBT_SETFOCUS, hook },
2724 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2725 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2726 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2727 { WM_SETFOCUS, sent },
2728 { 0 }
2729 };
2730 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2731 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2732 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2733 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
2734 { WM_NCCALCSIZE, sent|wparam, 1 },
2735 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2736 { WM_MOVE, sent|defwinproc },
2737 { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2738 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2739 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2740 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2741 /* FIXME: Wine creates an icon/title window while Windows doesn't */
2742 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2743 { 0 }
2744 };
2745 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2746 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2747 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2748 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
2749 { WM_NCCALCSIZE, sent|wparam, 1 },
2750 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2751 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2752 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2753 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2754 /* in MDI frame */
2755 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2756 { WM_NCCALCSIZE, sent|wparam, 1 },
2757 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2758 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2759 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2760 { 0 }
2761 };
2762
2763 static HWND mdi_client;
2764 static WNDPROC old_mdi_client_proc;
2765
2766 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2767 {
2768 struct message msg;
2769
2770 /* do not log painting messages */
2771 if (message != WM_PAINT &&
2772 message != WM_NCPAINT &&
2773 message != WM_SYNCPAINT &&
2774 message != WM_ERASEBKGND &&
2775 message != WM_NCHITTEST &&
2776 message != WM_GETTEXT &&
2777 message != WM_MDIGETACTIVE &&
2778 message != WM_GETICON &&
2779 message != WM_DEVICECHANGE)
2780 {
2781 trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2782
2783 switch (message)
2784 {
2785 case WM_WINDOWPOSCHANGING:
2786 case WM_WINDOWPOSCHANGED:
2787 {
2788 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2789
2790 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2791 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2792 winpos->hwnd, winpos->hwndInsertAfter,
2793 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2794 dump_winpos_flags(winpos->flags);
2795
2796 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2797 * in the high word for internal purposes
2798 */
2799 wParam = winpos->flags & 0xffff;
2800 /* We are not interested in the flags that don't match under XP and Win9x */
2801 wParam &= ~(SWP_NOZORDER);
2802 break;
2803 }
2804 }
2805
2806 msg.message = message;
2807 msg.flags = sent|wparam|lparam;
2808 msg.wParam = wParam;
2809 msg.lParam = lParam;
2810 add_message(&msg);
2811 }
2812
2813 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2814 }
2815
2816 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2817 {
2818 static long defwndproc_counter = 0;
2819 LRESULT ret;
2820 struct message msg;
2821
2822 /* do not log painting messages */
2823 if (message != WM_PAINT &&
2824 message != WM_NCPAINT &&
2825 message != WM_SYNCPAINT &&
2826 message != WM_ERASEBKGND &&
2827 message != WM_NCHITTEST &&
2828 message != WM_GETTEXT &&
2829 message != WM_GETICON &&
2830 message != WM_DEVICECHANGE)
2831 {
2832 trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2833
2834 switch (message)
2835 {
2836 case WM_WINDOWPOSCHANGING:
2837 case WM_WINDOWPOSCHANGED:
2838 {
2839 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2840
2841 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2842 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2843 winpos->hwnd, winpos->hwndInsertAfter,
2844 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2845 dump_winpos_flags(winpos->flags);
2846
2847 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2848 * in the high word for internal purposes
2849 */
2850 wParam = winpos->flags & 0xffff;
2851 /* We are not interested in the flags that don't match under XP and Win9x */
2852 wParam &= ~(SWP_NOZORDER);
2853 break;
2854 }
2855
2856 case WM_MDIACTIVATE:
2857 {
2858 HWND active, client = GetParent(hwnd);
2859
2860 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2861
2862 if (hwnd == (HWND)lParam) /* if we are being activated */
2863 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2864 else
2865 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2866 break;
2867 }
2868 }
2869
2870 msg.message = message;
2871 msg.flags = sent|wparam|lparam;
2872 if (defwndproc_counter) msg.flags |= defwinproc;
2873 msg.wParam = wParam;
2874 msg.lParam = lParam;
2875 add_message(&msg);
2876 }
2877
2878 defwndproc_counter++;
2879 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2880 defwndproc_counter--;
2881
2882 return ret;
2883 }
2884
2885 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2886 {
2887 static long defwndproc_counter = 0;
2888 LRESULT ret;
2889 struct message msg;
2890
2891 /* do not log painting messages */
2892 if (message != WM_PAINT &&
2893 message != WM_NCPAINT &&
2894 message != WM_SYNCPAINT &&
2895 message != WM_ERASEBKGND &&
2896 message != WM_NCHITTEST &&
2897 message != WM_GETTEXT &&
2898 message != WM_GETICON &&
2899 message != WM_DEVICECHANGE)
2900 {
2901 trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2902
2903 switch (message)
2904 {
2905 case WM_WINDOWPOSCHANGING:
2906 case WM_WINDOWPOSCHANGED:
2907 {
2908 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2909
2910 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2911 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2912 winpos->hwnd, winpos->hwndInsertAfter,
2913 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2914 dump_winpos_flags(winpos->flags);
2915
2916 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2917 * in the high word for internal purposes
2918 */
2919 wParam = winpos->flags & 0xffff;
2920 /* We are not interested in the flags that don't match under XP and Win9x */
2921 wParam &= ~(SWP_NOZORDER);
2922 break;
2923 }
2924 }
2925
2926 msg.message = message;
2927 msg.flags = sent|wparam|lparam;
2928 if (defwndproc_counter) msg.flags |= defwinproc;
2929 msg.wParam = wParam;
2930 msg.lParam = lParam;
2931 add_message(&msg);
2932 }
2933
2934 defwndproc_counter++;
2935 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2936 defwndproc_counter--;
2937
2938 return ret;
2939 }
2940
2941 static BOOL mdi_RegisterWindowClasses(void)
2942 {
2943 WNDCLASSA cls;
2944
2945 cls.style = 0;
2946 cls.lpfnWndProc = mdi_frame_wnd_proc;
2947 cls.cbClsExtra = 0;
2948 cls.cbWndExtra = 0;
2949 cls.hInstance = GetModuleHandleA(0);
2950 cls.hIcon = 0;
2951 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2952 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2953 cls.lpszMenuName = NULL;
2954 cls.lpszClassName = "MDI_frame_class";
2955 if (!RegisterClassA(&cls)) return FALSE;
2956
2957 cls.lpfnWndProc = mdi_child_wnd_proc;
2958 cls.lpszClassName = "MDI_child_class";
2959 if (!RegisterClassA(&cls)) return FALSE;
2960
2961 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
2962 old_mdi_client_proc = cls.lpfnWndProc;
2963 cls.hInstance = GetModuleHandleA(0);
2964 cls.lpfnWndProc = mdi_client_hook_proc;
2965 cls.lpszClassName = "MDI_client_class";
2966 if (!RegisterClassA(&cls)) assert(0);
2967
2968 return TRUE;
2969 }
2970
2971 static void test_mdi_messages(void)
2972 {
2973 MDICREATESTRUCTA mdi_cs;
2974 CLIENTCREATESTRUCT client_cs;
2975 HWND mdi_frame, mdi_child, mdi_child2, active_child;
2976 BOOL zoomed;
2977 HMENU hMenu = CreateMenu();
2978
2979 assert(mdi_RegisterWindowClasses());
2980
2981 flush_sequence();
2982
2983 trace("creating MDI frame window\n");
2984 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
2985 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2986 WS_MAXIMIZEBOX | WS_VISIBLE,
2987 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
2988 GetDesktopWindow(), hMenu,
2989 GetModuleHandleA(0), NULL);
2990 assert(mdi_frame);
2991 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
2992
2993 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2994 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
2995
2996 trace("creating MDI client window\n");
2997 client_cs.hWindowMenu = 0;
2998 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
2999 mdi_client = CreateWindowExA(0, "MDI_client_class",
3000 NULL,
3001 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3002 0, 0, 0, 0,
3003 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3004 assert(mdi_client);
3005 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3006
3007 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3008 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3009
3010 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3011 ok(!active_child, "wrong active MDI child %p\n", active_child);
3012 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3013
3014 SetFocus(0);
3015 flush_sequence();
3016
3017 trace("creating invisible MDI child window\n");
3018 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3019 WS_CHILD,
3020 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3021 mdi_client, 0, GetModuleHandleA(0), NULL);
3022 assert(mdi_child);
3023
3024 flush_sequence();
3025 ShowWindow(mdi_child, SW_SHOWNORMAL);
3026 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3027
3028 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3029 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3030
3031 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3032 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3033
3034 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3035 ok(!active_child, "wrong active MDI child %p\n", active_child);
3036 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3037
3038 ShowWindow(mdi_child, SW_HIDE);
3039 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3040 flush_sequence();
3041
3042 ShowWindow(mdi_child, SW_SHOW);
3043 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3044
3045 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3046 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3047
3048 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3049 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3050
3051 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3052 ok(!active_child, "wrong active MDI child %p\n", active_child);
3053 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3054
3055 DestroyWindow(mdi_child);
3056 flush_sequence();
3057
3058 trace("creating visible MDI child window\n");
3059 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3060 WS_CHILD | WS_VISIBLE,
3061 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3062 mdi_client, 0, GetModuleHandleA(0), NULL);
3063 assert(mdi_child);
3064 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3065
3066 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3067 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3068
3069 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3070 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3071
3072 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3073 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3074 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3075 flush_sequence();
3076
3077 DestroyWindow(mdi_child);
3078 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3079
3080 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3081 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3082
3083 /* Win2k: MDI client still returns a just destroyed child as active
3084 * Win9x: MDI client returns 0
3085 */
3086 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3087 ok(active_child == mdi_child || /* win2k */
3088 !active_child, /* win9x */
3089 "wrong active MDI child %p\n", active_child);
3090 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3091
3092 flush_sequence();
3093
3094 trace("creating invisible MDI child window\n");
3095 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3096 WS_CHILD,
3097 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3098 mdi_client, 0, GetModuleHandleA(0), NULL);
3099 assert(mdi_child2);
3100 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3101
3102 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3103 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3104
3105 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3106 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3107
3108 /* Win2k: MDI client still returns a just destroyed child as active
3109 * Win9x: MDI client returns mdi_child2
3110 */
3111 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3112 ok(active_child == mdi_child || /* win2k */
3113 active_child == mdi_child2, /* win9x */
3114 "wrong active MDI child %p\n", active_child);
3115 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3116 flush_sequence();
3117
3118 ShowWindow(mdi_child2, SW_MAXIMIZE);
3119 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3120
3121 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3122 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3123
3124 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3125 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3126 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3127 flush_sequence();
3128
3129 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3130 ok(GetFocus() == mdi_child2 || /* win2k */
3131 GetFocus() == 0, /* win9x */
3132 "wrong focus window %p\n", GetFocus());
3133
3134 SetFocus(0);
3135 flush_sequence();
3136
3137 ShowWindow(mdi_child2, SW_HIDE);
3138 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3139
3140 ShowWindow(mdi_child2, SW_RESTORE);
3141 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3142 flush_sequence();
3143
3144 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3145 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3146
3147 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3148 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3149 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3150 flush_sequence();
3151
3152 SetFocus(0);
3153 flush_sequence();
3154
3155 ShowWindow(mdi_child2, SW_HIDE);
3156 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3157
3158 ShowWindow(mdi_child2, SW_SHOW);
3159 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3160
3161 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3162 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3163
3164 ShowWindow(mdi_child2, SW_MAXIMIZE);
3165 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3166
3167 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3168 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3169
3170 ShowWindow(mdi_child2, SW_RESTORE);
3171 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3172
3173 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3174 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3175
3176 ShowWindow(mdi_child2, SW_MINIMIZE);
3177 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3178
3179 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3180 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3181
3182 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3183 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3184 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3185 flush_sequence();
3186
3187 ShowWindow(mdi_child2, SW_RESTORE);
3188 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3189
3190 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3191 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3192
3193 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3194 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3195 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3196 flush_sequence();
3197
3198 SetFocus(0);
3199 flush_sequence();
3200
3201 ShowWindow(mdi_child2, SW_HIDE);
3202 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3203
3204 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3205 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3206
3207 DestroyWindow(mdi_child2);
3208 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3209
3210 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3211 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3212
3213 /* test for maximized MDI children */
3214 trace("creating maximized visible MDI child window 1\n");
3215 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3216 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3217 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3218 mdi_client, 0, GetModuleHandleA(0), NULL);
3219 assert(mdi_child);
3220 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3221 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3222
3223 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3224 ok(GetFocus() == mdi_child || /* win2k */
3225 GetFocus() == 0, /* win9x */
3226 "wrong focus window %p\n", GetFocus());
3227
3228 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3229 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3230 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3231 flush_sequence();
3232
3233 trace("creating maximized visible MDI child window 2\n");
3234 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3235 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3236 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3237 mdi_client, 0, GetModuleHandleA(0), NULL);
3238 assert(mdi_child2);
3239 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3240 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3241 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3242
3243 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3244 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3245
3246 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3247 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3248 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3249 flush_sequence();
3250
3251 trace("destroying maximized visible MDI child window 2\n");
3252 DestroyWindow(mdi_child2);
3253 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3254
3255 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3256
3257 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3258 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3259
3260 /* Win2k: MDI client still returns a just destroyed child as active
3261 * Win9x: MDI client returns 0
3262 */
3263 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3264 ok(active_child == mdi_child2 || /* win2k */
3265 !active_child, /* win9x */
3266 "wrong active MDI child %p\n", active_child);
3267 flush_sequence();
3268
3269 ShowWindow(mdi_child, SW_MAXIMIZE);
3270 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3271 flush_sequence();
3272
3273 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3274 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3275
3276 trace("re-creating maximized visible MDI child window 2\n");
3277 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3278 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3279 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3280 mdi_client, 0, GetModuleHandleA(0), NULL);
3281 assert(mdi_child2);
3282 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3283 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3284 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3285
3286 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3287 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3288
3289 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3290 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3291 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3292 flush_sequence();
3293
3294 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3295 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3296 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3297
3298 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3299 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3300 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3301
3302 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3303 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3304 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3305 flush_sequence();
3306
3307 DestroyWindow(mdi_child);
3308 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3309
3310 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3311 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3312
3313 /* Win2k: MDI client still returns a just destroyed child as active
3314 * Win9x: MDI client returns 0
3315 */
3316 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3317 ok(active_child == mdi_child || /* win2k */
3318 !active_child, /* win9x */
3319 "wrong active MDI child %p\n", active_child);
3320 flush_sequence();
3321
3322 trace("creating maximized invisible MDI child window\n");
3323 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3324 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3325 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3326 mdi_client, 0, GetModuleHandleA(0), NULL);
3327 assert(mdi_child2);
3328 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE);
3329 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3330 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3331 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3332
3333 /* Win2k: MDI client still returns a just destroyed child as active
3334 * Win9x: MDI client returns 0
3335 */
3336 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3337 ok(active_child == mdi_child || /* win2k */
3338 !active_child, /* win9x */
3339 "wrong active MDI child %p\n", active_child);
3340 flush_sequence();
3341
3342 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3343 ShowWindow(mdi_child2, SW_MAXIMIZE);
3344 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3345 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3346 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3347 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3348
3349 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3350 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3351 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3352 flush_sequence();
3353
3354 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3355 flush_sequence();
3356
3357 /* end of test for maximized MDI children */
3358 SetFocus(0);
3359 flush_sequence();
3360 trace("creating maximized visible MDI child window 1(Switch test)\n");
3361 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3362 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3363 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3364 mdi_client, 0, GetModuleHandleA(0), NULL);
3365 assert(mdi_child);
3366 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3367 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3368
3369 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3370 ok(GetFocus() == mdi_child || /* win2k */
3371 GetFocus() == 0, /* win9x */
3372 "wrong focus window %p(Switch test)\n", GetFocus());
3373
3374 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3375 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3376 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3377 flush_sequence();
3378
3379 trace("creating maximized visible MDI child window 2(Switch test)\n");
3380 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3381 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3382 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3383 mdi_client, 0, GetModuleHandleA(0), NULL);
3384 assert(mdi_child2);
3385 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3386
3387 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3388 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3389
3390 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3391 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3392
3393 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3394 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3395 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3396 flush_sequence();
3397
3398 trace("Switch child window.\n");
3399 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3400 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3401 trace("end of test for switch maximized MDI children\n");
3402 flush_sequence();
3403
3404 /* Prepare for switching test of not maximized MDI children */
3405 ShowWindow( mdi_child, SW_NORMAL );
3406 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3407 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3408 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3409 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3410 flush_sequence();
3411
3412 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3413 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3414 trace("end of test for switch not maximized MDI children\n");
3415 flush_sequence();
3416
3417 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3418 flush_sequence();
3419
3420 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3421 flush_sequence();
3422
3423 SetFocus(0);
3424 flush_sequence();
3425 /* end of tests for switch maximized/not maximized MDI children */
3426
3427 mdi_cs.szClass = "MDI_child_Class";
3428 mdi_cs.szTitle = "MDI child";
3429 mdi_cs.hOwner = GetModuleHandleA(0);
3430 mdi_cs.x = 0;
3431 mdi_cs.y = 0;
3432 mdi_cs.cx = CW_USEDEFAULT;
3433 mdi_cs.cy = CW_USEDEFAULT;
3434 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3435 mdi_cs.lParam = 0;
3436 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3437 ok(mdi_child != 0, "MDI child creation failed\n");
3438 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3439
3440 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3441
3442 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3443 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3444
3445 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3446 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3447 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3448
3449 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3450 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3451 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3452 flush_sequence();
3453
3454 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3455 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3456
3457 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3458 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3459 ok(!active_child, "wrong active MDI child %p\n", active_child);
3460
3461 SetFocus(0);
3462 flush_sequence();
3463
3464 DestroyWindow(mdi_client);
3465 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3466
3467 /* test maximization of MDI child with invisible parent */
3468 client_cs.hWindowMenu = 0;
3469 mdi_client = CreateWindow("MDI_client_class",
3470 NULL,
3471 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3472 0, 0, 660, 430,
3473 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3474 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3475
3476 ShowWindow(mdi_client, SW_HIDE);
3477 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3478
3479 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3480 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3481 0, 0, 650, 440,
3482 mdi_client, 0, GetModuleHandleA(0), NULL);
3483 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3484
3485 SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3486 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3487 zoomed = IsZoomed(mdi_child);
3488 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3489
3490 ShowWindow(mdi_client, SW_SHOW);
3491 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3492
3493 DestroyWindow(mdi_child);
3494 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3495
3496 /* end of test for maximization of MDI child with invisible parent */
3497
3498 DestroyWindow(mdi_client);
3499 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3500
3501 DestroyWindow(mdi_frame);
3502 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3503 }
3504 /************************* End of MDI test **********************************/
3505
3506 static void test_WM_SETREDRAW(HWND hwnd)
3507 {
3508 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3509
3510 flush_sequence();
3511
3512 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3513 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3514
3515 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3516 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3517
3518 flush_sequence();
3519 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3520 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3521
3522 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3523 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3524
3525 /* restore original WS_VISIBLE state */
3526 SetWindowLongA(hwnd, GWL_STYLE, style);
3527
3528 flush_sequence();
3529 }
3530
3531 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3532 {
3533 struct message msg;
3534
3535 trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3536
3537 /* explicitly ignore WM_GETICON message */
3538 if (message == WM_GETICON) return 0;
3539
3540 switch (message)
3541 {
3542 /* ignore */
3543 case WM_MOUSEMOVE:
3544 case WM_SETCURSOR:
3545 case WM_DEVICECHANGE:
3546 return 0;
3547 case WM_NCHITTEST:
3548 return HTCLIENT;
3549
3550 case WM_WINDOWPOSCHANGING:
3551 case WM_WINDOWPOSCHANGED:
3552 {
3553 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3554
3555 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3556 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3557 winpos->hwnd, winpos->hwndInsertAfter,
3558 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3559 dump_winpos_flags(winpos->flags);
3560
3561 /* Log only documented flags, win2k uses 0x1000 and 0x2000
3562 * in the high word for internal purposes
3563 */
3564 wParam = winpos->flags & 0xffff;
3565 /* We are not interested in the flags that don't match under XP and Win9x */
3566 wParam &= ~(SWP_NOZORDER);
3567 break;
3568 }
3569 }
3570
3571 msg.message = message;
3572 msg.flags = sent|wparam|lparam;
3573 msg.wParam = wParam;
3574 msg.lParam = lParam;
3575 add_message(&msg);
3576
3577 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3578 if (message == WM_TIMER) EndDialog( hwnd, 0 );
3579 return 0;
3580 }
3581
3582 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3583 {
3584 DWORD style, exstyle;
3585 INT xmin, xmax;
3586 BOOL ret;
3587
3588 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3589 style = GetWindowLongA(hwnd, GWL_STYLE);
3590 /* do not be confused by WS_DLGFRAME set */
3591 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3592
3593 if (clear) ok(style & clear, "style %08x should be set\n", clear);
3594 if (set) ok(!(style & set), "style %08x should not be set\n", set);
3595
3596 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3597 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3598 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3599 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3600 else
3601 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3602
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);
3606
3607 /* a subsequent call should do nothing */
3608 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3609 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3610 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3611
3612 xmin = 0xdeadbeef;
3613 xmax = 0xdeadbeef;
3614 trace("Ignore GetScrollRange error below if you are on Win9x\n");
3615 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3616 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3617 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3618 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3619 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3620 }
3621
3622 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3623 {
3624 DWORD style, exstyle;
3625 SCROLLINFO si;
3626 BOOL ret;
3627
3628 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3629 style = GetWindowLongA(hwnd, GWL_STYLE);
3630 /* do not be confused by WS_DLGFRAME set */
3631 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3632
3633 if (clear) ok(style & clear, "style %08x should be set\n", clear);
3634 if (set) ok(!(style & set), "style %08x should not be set\n", set);
3635
3636 si.cbSize = sizeof(si);
3637 si.fMask = SIF_RANGE;
3638 si.nMin = min;
3639 si.nMax = max;
3640 SetScrollInfo(hwnd, ctl, &si, TRUE);
3641 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3642 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3643 else
3644 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3645
3646 style = GetWindowLongA(hwnd, GWL_STYLE);
3647 if (set) ok(style & set, "style %08x should be set\n", set);
3648 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3649
3650 /* a subsequent call should do nothing */
3651 SetScrollInfo(hwnd, ctl, &si, TRUE);
3652 if (style & WS_HSCROLL)
3653 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3654 else if (style & WS_VSCROLL)
3655 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3656 else
3657 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3658
3659 si.fMask = SIF_PAGE;
3660 si.nPage = 5;
3661 SetScrollInfo(hwnd, ctl, &si, FALSE);
3662 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3663
3664 si.fMask = SIF_POS;
3665 si.nPos = max - 1;
3666 SetScrollInfo(hwnd, ctl, &si, FALSE);
3667 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3668
3669 si.fMask = SIF_RANGE;
3670 si.nMin = 0xdeadbeef;
3671 si.nMax = 0xdeadbeef;
3672 ret = GetScrollInfo(hwnd, ctl, &si);
3673 ok( ret, "GetScrollInfo error %d\n", GetLastError());
3674 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3675 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3676 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3677 }
3678
3679 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3680 static void test_scroll_messages(HWND hwnd)
3681 {
3682 SCROLLINFO si;
3683 INT min, max;
3684 BOOL ret;
3685
3686 min = 0xdeadbeef;
3687 max = 0xdeadbeef;
3688 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3689 ok( ret, "GetScrollRange error %d\n", GetLastError());
3690 if (sequence->message != WmGetScrollRangeSeq[0].message)
3691 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3692 /* values of min and max are undefined */
3693 flush_sequence();
3694
3695 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3696 ok( ret, "SetScrollRange error %d\n", GetLastError());
3697 if (sequence->message != WmSetScrollRangeSeq[0].message)
3698 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3699 flush_sequence();
3700
3701 min = 0xdeadbeef;
3702 max = 0xdeadbeef;
3703 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3704 ok( ret, "GetScrollRange error %d\n", GetLastError());
3705 if (sequence->message != WmGetScrollRangeSeq[0].message)
3706 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3707 /* values of min and max are undefined */
3708 flush_sequence();
3709
3710 si.cbSize = sizeof(si);
3711 si.fMask = SIF_RANGE;
3712 si.nMin = 20;
3713 si.nMax = 160;
3714 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3715 if (sequence->message != WmSetScrollRangeSeq[0].message)
3716 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3717 flush_sequence();
3718
3719 si.fMask = SIF_PAGE;
3720 si.nPage = 10;
3721 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3722 if (sequence->message != WmSetScrollRangeSeq[0].message)
3723 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3724 flush_sequence();
3725
3726 si.fMask = SIF_POS;
3727 si.nPos = 20;
3728 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3729 if (sequence->message != WmSetScrollRangeSeq[0].message)
3730 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3731 flush_sequence();
3732
3733 si.fMask = SIF_RANGE;
3734 si.nMin = 0xdeadbeef;
3735 si.nMax = 0xdeadbeef;
3736 ret = GetScrollInfo(hwnd, SB_CTL, &si);
3737 ok( ret, "GetScrollInfo error %d\n", GetLastError());
3738 if (sequence->message != WmGetScrollInfoSeq[0].message)
3739 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3740 /* values of min and max are undefined */
3741 flush_sequence();
3742
3743 /* set WS_HSCROLL */
3744 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3745 /* clear WS_HSCROLL */
3746 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3747
3748 /* set WS_HSCROLL */
3749 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3750 /* clear WS_HSCROLL */
3751 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3752
3753 /* set WS_VSCROLL */
3754 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3755 /* clear WS_VSCROLL */
3756 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3757
3758 /* set WS_VSCROLL */
3759 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3760 /* clear WS_VSCROLL */
3761 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3762 }
3763
3764 static void test_showwindow(void)
3765 {
3766 HWND hwnd, hchild;
3767 RECT rc;
3768
3769 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3770 100, 100, 200, 200, 0, 0, 0, NULL);
3771 ok (hwnd != 0, "Failed to create overlapped window\n");
3772 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3773 0, 0, 10, 10, hwnd, 0, 0, NULL);
3774 ok (hchild != 0, "Failed to create child\n");
3775 flush_sequence();
3776
3777 /* ShowWindow( SW_SHOWNA) for invisible top level window */
3778 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3779 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3780 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3781 trace("done\n");
3782
3783 /* ShowWindow( SW_SHOWNA) for now visible top level window */
3784 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3785 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3786 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3787 trace("done\n");
3788 /* back to invisible */
3789 ShowWindow(hchild, SW_HIDE);
3790 ShowWindow(hwnd, SW_HIDE);
3791 flush_sequence();
3792 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
3793 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3794 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3795 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3796 trace("done\n");
3797 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
3798 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3799 flush_sequence();
3800 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3801 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3802 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3803 trace("done\n");
3804 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3805 ShowWindow( hwnd, SW_SHOW);
3806 flush_sequence();
3807 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3808 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3809 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3810 trace("done\n");
3811
3812 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3813 ShowWindow( hchild, SW_HIDE);
3814 flush_sequence();
3815 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3816 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3817 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3818 trace("done\n");
3819
3820 SetCapture(hchild);
3821 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3822 DestroyWindow(hchild);
3823 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3824
3825 DestroyWindow(hwnd);
3826 flush_sequence();
3827
3828 /* Popup windows */
3829 /* Test 1:
3830 * 1. Create invisible maximized popup window.
3831 * 2. Move and resize it.
3832 * 3. Show it maximized.
3833 */
3834 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3835 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3836 100, 100, 200, 200, 0, 0, 0, NULL);
3837 ok (hwnd != 0, "Failed to create popup window\n");
3838 ok(IsZoomed(hwnd), "window should be maximized\n");
3839 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3840 trace("done\n");
3841
3842 GetWindowRect(hwnd, &rc);
3843 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3844 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3845 "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3846 rc.left, rc.top, rc.right, rc.bottom);
3847 /* Reset window's size & position */
3848 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3849 ok(IsZoomed(hwnd), "window should be maximized\n");
3850 flush_sequence();
3851
3852 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3853 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3854 ok(IsZoomed(hwnd), "window should be maximized\n");
3855 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3856 trace("done\n");
3857
3858 GetWindowRect(hwnd, &rc);
3859 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3860 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3861 "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3862 rc.left, rc.top, rc.right, rc.bottom);
3863 DestroyWindow(hwnd);
3864 flush_sequence();
3865
3866 /* Test 2:
3867 * 1. Create invisible maximized popup window.
3868 * 2. Show it maximized.
3869 */
3870 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3871 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3872 100, 100, 200, 200, 0, 0, 0, NULL);
3873 ok (hwnd != 0, "Failed to create popup window\n");
3874 ok(IsZoomed(hwnd), "window should be maximized\n");
3875 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3876 trace("done\n");
3877
3878 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3879 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3880 ok(IsZoomed(hwnd), "window should be maximized\n");
3881 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
3882 trace("done\n");
3883 DestroyWindow(hwnd);
3884 flush_sequence();
3885
3886 /* Test 3:
3887 * 1. Create visible maximized popup window.
3888 */
3889 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
3890 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3891 100, 100, 200, 200, 0, 0, 0, NULL);
3892 ok (hwnd != 0, "Failed to create popup window\n");
3893 ok(IsZoomed(hwnd), "window should be maximized\n");
3894 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3895 trace("done\n");
3896 DestroyWindow(hwnd);
3897 flush_sequence();
3898
3899 /* Test 4:
3900 * 1. Create visible popup window.
3901 * 2. Maximize it.
3902 */
3903 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
3904 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
3905 100, 100, 200, 200, 0, 0, 0, NULL);
3906 ok (hwnd != 0, "Failed to create popup window\n");
3907 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
3908 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
3909 trace("done\n");
3910
3911 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
3912 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3913 ok(IsZoomed(hwnd), "window should be maximized\n");
3914 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3915 trace("done\n");
3916 DestroyWindow(hwnd);
3917 flush_sequence();
3918 }
3919
3920 static void test_sys_menu(void)
3921 {
3922 HWND hwnd;
3923 HMENU hmenu;
3924 UINT state;
3925
3926 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3927 100, 100, 200, 200, 0, 0, 0, NULL);
3928 ok (hwnd != 0, "Failed to create overlapped window\n");
3929
3930 flush_sequence();
3931
3932 /* test existing window without CS_NOCLOSE style */
3933 hmenu = GetSystemMenu(hwnd, FALSE);
3934 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3935
3936 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3937 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3938 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3939
3940 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
3941 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3942
3943 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3944 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3945 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
3946
3947 EnableMenuItem(hmenu, SC_CLOSE, 0);
3948 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3949
3950 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3951 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3952 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3953
3954 /* test whether removing WS_SYSMENU destroys a system menu */
3955 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
3956 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3957 flush_sequence();
3958 hmenu = GetSystemMenu(hwnd, FALSE);
3959 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3960
3961 DestroyWindow(hwnd);
3962
3963 /* test new window with CS_NOCLOSE style */
3964 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3965 100, 100, 200, 200, 0, 0, 0, NULL);
3966 ok (hwnd != 0, "Failed to create overlapped window\n");
3967
3968 hmenu = GetSystemMenu(hwnd, FALSE);
3969 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3970
3971 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3972 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3973
3974 DestroyWindow(hwnd);
3975
3976 /* test new window without WS_SYSMENU style */
3977 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
3978 100, 100, 200, 200, 0, 0, 0, NULL);
3979 ok(hwnd != 0, "Failed to create overlapped window\n");
3980
3981 hmenu = GetSystemMenu(hwnd, FALSE);
3982 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
3983
3984 DestroyWindow(hwnd);
3985 }
3986
3987 /* For shown WS_OVERLAPPEDWINDOW */
3988 static const struct message WmSetIcon_1[] = {
3989 { WM_SETICON, sent },
3990 { 0x00AE, sent|defwinproc|optional }, /* XP */
3991 { WM_GETTEXT, sent|defwinproc|optional },
3992 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
3993 { 0 }
3994 };
3995
3996 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
3997 static const struct message WmSetIcon_2[] = {
3998 { WM_SETICON, sent },
3999 { 0 }
4000 };
4001
4002 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4003 static const struct message WmInitEndSession[] = {
4004 { 0x003B, sent },
4005 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4006 { 0 }
4007 };
4008
4009 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4010 static const struct message WmInitEndSession_2[] = {
4011 { 0x003B, sent },
4012 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4013 { 0 }
4014 };
4015
4016 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4017 static const struct message WmInitEndSession_3[] = {
4018 { 0x003B, sent },
4019 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4020 { 0 }
4021 };
4022
4023 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4024 static const struct message WmInitEndSession_4[] = {
4025 { 0x003B, sent },
4026 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4027 { 0 }
4028 };
4029
4030 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4031 static const struct message WmInitEndSession_5[] = {
4032 { 0x003B, sent },
4033 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 1, ENDSESSION_LOGOFF },
4034 { 0 }
4035 };
4036
4037 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4038 {
4039 DWORD ret;
4040 MSG msg;
4041
4042 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4043 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4044
4045 PostMessageA(hwnd, WM_USER, 0, 0);
4046
4047 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4048 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4049
4050 ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4051 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4052
4053 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4054 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4055
4056 PostMessageA(hwnd, WM_USER, 0, 0);
4057
4058 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4059 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4060
4061 ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4062 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4063
4064 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4065 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4066 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4067
4068 PostMessageA(hwnd, WM_USER, 0, 0);
4069
4070 /* new incoming message causes it to become signaled again */
4071 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4072 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4073
4074 ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4075 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4076 ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4077 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4078 }
4079
4080 /* test if we receive the right sequence of messages */
4081 static void test_messages(void)
4082 {
4083 HWND hwnd, hparent, hchild;
4084 HWND hchild2, hbutton;
4085 HMENU hmenu;
4086 MSG msg;
4087 LRESULT res;
4088
4089 flush_sequence();
4090
4091 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4092 100, 100, 200, 200, 0, 0, 0, NULL);
4093 ok (hwnd != 0, "Failed to create overlapped window\n");
4094 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4095
4096 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4097 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4098 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4099
4100 /* test WM_SETREDRAW on a not visible top level window */
4101 test_WM_SETREDRAW(hwnd);
4102
4103 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4104 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4105 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4106
4107 ok(GetActiveWindow() == hwnd, "window should be active\n");
4108 ok(GetFocus() == hwnd, "window should have input focus\n");
4109 ShowWindow(hwnd, SW_HIDE);
4110 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
4111
4112 ShowWindow(hwnd, SW_SHOW);
4113 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4114
4115 ShowWindow(hwnd, SW_HIDE);
4116 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4117
4118 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4119 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4120
4121 ShowWindow(hwnd, SW_RESTORE);
4122 /* FIXME: add ok_sequence() here */
4123 flush_sequence();
4124
4125 ShowWindow(hwnd, SW_MINIMIZE);
4126 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4127 flush_sequence();
4128
4129 ShowWindow(hwnd, SW_RESTORE);
4130 /* FIXME: add ok_sequence() here */
4131 flush_sequence();
4132
4133 ShowWindow(hwnd, SW_SHOW);
4134 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4135
4136 ok(GetActiveWindow() == hwnd, "window should be active\n");
4137 ok(GetFocus() == hwnd, "window should have input focus\n");
4138 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4139 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4140 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4141 ok(GetActiveWindow() == hwnd, "window should still be active\n");
4142
4143 /* test WM_SETREDRAW on a visible top level window */
4144 ShowWindow(hwnd, SW_SHOW);
4145 test_WM_SETREDRAW(hwnd);
4146
4147 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4148 test_scroll_messages(hwnd);
4149
4150 /* test resizing and moving */
4151 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4152 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4153 flush_events();
4154 flush_sequence();
4155 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4156 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4157 flush_events();
4158 flush_sequence();
4159 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER );
4160 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4161 flush_events();
4162 flush_sequence();
4163
4164 /* popups don't get WM_GETMINMAXINFO */
4165 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4166 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4167 flush_sequence();
4168 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4169 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4170
4171 DestroyWindow(hwnd);
4172 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4173
4174 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4175 100, 100, 200, 200, 0, 0, 0, NULL);
4176 ok (hparent != 0, "Failed to create parent window\n");
4177 flush_sequence();
4178
4179 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4180 0, 0, 10, 10, hparent, 0, 0, NULL);
4181 ok (hchild != 0, "Failed to create child window\n");
4182 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4183 DestroyWindow(hchild);
4184 flush_sequence();
4185
4186 /* visible child window with a caption */
4187 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4188 WS_CHILD | WS_VISIBLE | WS_CAPTION,
4189 0, 0, 10, 10, hparent, 0, 0, NULL);
4190 ok (hchild != 0, "Failed to create child window\n");
4191 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4192
4193 trace("testing scroll APIs on a visible child window %p\n", hchild);
4194 test_scroll_messages(hchild);
4195
4196 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4197 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4198
4199 DestroyWindow(hchild);
4200 flush_sequence();
4201
4202 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4203 0, 0, 10, 10, hparent, 0, 0, NULL);
4204 ok (hchild != 0, "Failed to create child window\n");
4205 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4206
4207 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4208 100, 100, 50, 50, hparent, 0, 0, NULL);
4209 ok (hchild2 != 0, "Failed to create child2 window\n");
4210 flush_sequence();
4211
4212 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4213 0, 100, 50, 50, hchild, 0, 0, NULL);
4214 ok (hbutton != 0, "Failed to create button window\n");
4215
4216 /* test WM_SETREDRAW on a not visible child window */
4217 test_WM_SETREDRAW(hchild);
4218
4219 ShowWindow(hchild, SW_SHOW);
4220 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4221
4222 /* check parent messages too */
4223 log_all_parent_messages++;
4224 ShowWindow(hchild, SW_HIDE);
4225 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4226 log_all_parent_messages--;
4227
4228 ShowWindow(hchild, SW_SHOW);
4229 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4230
4231 ShowWindow(hchild, SW_HIDE);
4232 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4233
4234 ShowWindow(hchild, SW_SHOW);
4235 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4236
4237 /* test WM_SETREDRAW on a visible child window */
4238 test_WM_SETREDRAW(hchild);
4239
4240 log_all_parent_messages++;
4241 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4242 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4243 log_all_parent_messages--;
4244
4245 ShowWindow(hchild, SW_HIDE);
4246 flush_sequence();
4247 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4248 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4249
4250 ShowWindow(hchild, SW_HIDE);
4251 flush_sequence();
4252 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4253 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4254
4255 /* DestroyWindow sequence below expects that a child has focus */
4256 SetFocus(hchild);
4257 flush_sequence();
4258
4259 DestroyWindow(hchild);
4260 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4261 DestroyWindow(hchild2);
4262 DestroyWindow(hbutton);
4263
4264 flush_sequence();
4265 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4266 0, 0, 100, 100, hparent, 0, 0, NULL);
4267 ok (hchild != 0, "Failed to create child popup window\n");
4268 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4269 DestroyWindow(hchild);
4270
4271 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4272 flush_sequence();
4273 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4274 0, 0, 100, 100, hparent, 0, 0, NULL);
4275 ok (hchild != 0, "Failed to create popup window\n");
4276 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4277 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4278 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4279 flush_sequence();
4280 ShowWindow(hchild, SW_SHOW);
4281 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4282 flush_sequence();
4283 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4284 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4285 flush_sequence();
4286 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4287 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", TRUE);
4288 DestroyWindow(hchild);
4289
4290 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4291 * changes nothing in message sequences.
4292 */
4293 flush_sequence();
4294 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4295 0, 0, 100, 100, hparent, 0, 0, NULL);
4296 ok (hchild != 0, "Failed to create popup window\n");
4297 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4298 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4299 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4300 flush_sequence();
4301 ShowWindow(hchild, SW_SHOW);
4302 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4303 flush_sequence();
4304 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4305 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4306 DestroyWindow(hchild);
4307
4308 flush_sequence();
4309 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4310 0, 0, 100, 100, hparent, 0, 0, NULL);
4311 ok(hwnd != 0, "Failed to create custom dialog window\n");
4312 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4313
4314 /*
4315 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4316 test_scroll_messages(hwnd);
4317 */
4318
4319 flush_sequence();
4320
4321 test_def_id = 1;
4322 SendMessage(hwnd, WM_NULL, 0, 0);
4323
4324 flush_sequence();
4325 after_end_dialog = 1;
4326 EndDialog( hwnd, 0 );
4327 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4328
4329 DestroyWindow(hwnd);
4330 after_end_dialog = 0;
4331 test_def_id = 0;
4332
4333 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4334 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4335 ok(hwnd != 0, "Failed to create custom dialog window\n");
4336 flush_sequence();
4337 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4338 ShowWindow(hwnd, SW_SHOW);
4339 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4340 DestroyWindow(hwnd);
4341
4342 flush_sequence();
4343 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4344 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4345
4346 DestroyWindow(hparent);
4347 flush_sequence();
4348
4349 /* Message sequence for SetMenu */
4350 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4351 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4352
4353 hmenu = CreateMenu();
4354 ok (hmenu != 0, "Failed to create menu\n");
4355 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4356 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4357 100, 100, 200, 200, 0, hmenu, 0, NULL);
4358 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4359 ok (SetMenu(hwnd, 0), "SetMenu\n");
4360 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4361 ok (SetMenu(hwnd, 0), "SetMenu\n");
4362 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4363 ShowWindow(hwnd, SW_SHOW);
4364 UpdateWindow( hwnd );
4365 flush_events();
4366 flush_sequence();
4367 ok (SetMenu(hwnd, 0), "SetMenu\n");
4368 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4369 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4370 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4371
4372 UpdateWindow( hwnd );
4373 flush_events();
4374 flush_sequence();
4375 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4376 flush_events();
4377 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4378
4379 DestroyWindow(hwnd);
4380 flush_sequence();
4381
4382 /* Message sequence for EnableWindow */
4383 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4384 100, 100, 200, 200, 0, 0, 0, NULL);
4385 ok (hparent != 0, "Failed to create parent window\n");
4386 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4387 0, 0, 10, 10, hparent, 0, 0, NULL);
4388 ok (hchild != 0, "Failed to create child window\n");
4389
4390 SetFocus(hchild);
4391 flush_events();
4392 flush_sequence();
4393
4394 EnableWindow(hparent, FALSE);
4395 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4396
4397 EnableWindow(hparent, TRUE);
4398 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4399
4400 flush_events();
4401 flush_sequence();
4402
4403 test_MsgWaitForMultipleObjects(hparent);
4404
4405 /* the following test causes an exception in user.exe under win9x */
4406 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4407 {
4408 DestroyWindow(hparent);
4409 flush_sequence();
4410 return;
4411 }
4412 PostMessageW( hparent, WM_USER+1, 0, 0 );
4413 /* PeekMessage(NULL) fails, but still removes the message */
4414 SetLastError(0xdeadbeef);
4415 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4416 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4417 GetLastError() == 0xdeadbeef, /* NT4 */
4418 "last error is %d\n", GetLastError() );
4419 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4420 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4421
4422 DestroyWindow(hchild);
4423 DestroyWindow(hparent);
4424 flush_sequence();
4425
4426 /* Message sequences for WM_SETICON */
4427 trace("testing WM_SETICON\n");
4428 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4429 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4430 NULL, NULL, 0);
4431 ShowWindow(hwnd, SW_SHOW);
4432 UpdateWindow(hwnd);
4433 flush_events();
4434 flush_sequence();
4435 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4436 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4437
4438 ShowWindow(hwnd, SW_HIDE);
4439 flush_events();
4440 flush_sequence();
4441 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4442 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4443 DestroyWindow(hwnd);
4444 flush_sequence();
4445
4446 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4447 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4448 NULL, NULL, 0);
4449 ShowWindow(hwnd, SW_SHOW);
4450 UpdateWindow(hwnd);
4451 flush_events();
4452 flush_sequence();
4453 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4454 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4455
4456 ShowWindow(hwnd, SW_HIDE);
4457 flush_events();
4458 flush_sequence();
4459 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4460 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4461
4462 flush_sequence();
4463 res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4464 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4465 todo_wine
4466 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4467 res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4468 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4469 todo_wine
4470 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4471 res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4472 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4473 todo_wine
4474 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4475
4476 flush_sequence();
4477 res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4478 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4479 todo_wine
4480 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4481 res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4482 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4483 todo_wine
4484 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4485
4486 res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4487 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4488 todo_wine
4489 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4490
4491 res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4492 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4493 todo_wine
4494 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4495
4496 DestroyWindow(hwnd);
4497 flush_sequence();
4498 }
4499
4500 static void invisible_parent_tests(void)
4501 {
4502 HWND hparent, hchild;
4503
4504 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4505 100, 100, 200, 200, 0, 0, 0, NULL);
4506 ok (hparent != 0, "Failed to create parent window\n");
4507 flush_sequence();
4508
4509 /* test showing child with hidden parent */
4510
4511 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4512 0, 0, 10, 10, hparent, 0, 0, NULL);
4513 ok (hchild != 0, "Failed to create child window\n");
4514 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4515
4516 ShowWindow( hchild, SW_MINIMIZE );
4517 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4518 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4519 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4520
4521 /* repeat */
4522 flush_events();
4523 flush_sequence();
4524 ShowWindow( hchild, SW_MINIMIZE );
4525 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4526
4527 DestroyWindow(hchild);
4528 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4529 0, 0, 10, 10, hparent, 0, 0, NULL);
4530 flush_sequence();
4531
4532 ShowWindow( hchild, SW_MAXIMIZE );
4533 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) 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");
4536
4537 /* repeat */
4538 flush_events();
4539 flush_sequence();
4540 ShowWindow( hchild, SW_MAXIMIZE );
4541 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4542
4543 DestroyWindow(hchild);
4544 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4545 0, 0, 10, 10, hparent, 0, 0, NULL);
4546 flush_sequence();
4547
4548 ShowWindow( hchild, SW_RESTORE );
4549 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4550 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4551 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4552
4553 DestroyWindow(hchild);
4554 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4555 0, 0, 10, 10, hparent, 0, 0, NULL);
4556 flush_sequence();
4557
4558 ShowWindow( hchild, SW_SHOWMINIMIZED );
4559 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4560 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4561 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4562
4563 /* repeat */
4564 flush_events();
4565 flush_sequence();
4566 ShowWindow( hchild, SW_SHOWMINIMIZED );
4567 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4568
4569 DestroyWindow(hchild);
4570 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4571 0, 0, 10, 10, hparent, 0, 0, NULL);
4572 flush_sequence();
4573
4574 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4575 ShowWindow( hchild, SW_SHOWMAXIMIZED );
4576 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4577 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4578 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4579
4580 DestroyWindow(hchild);
4581 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4582 0, 0, 10, 10, hparent, 0, 0, NULL);
4583 flush_sequence();
4584
4585 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4586 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4587 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4588 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4589
4590 /* repeat */
4591 flush_events();
4592 flush_sequence();
4593 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4594 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4595
4596 DestroyWindow(hchild);
4597 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4598 0, 0, 10, 10, hparent, 0, 0, NULL);
4599 flush_sequence();
4600
4601 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4602 ShowWindow( hchild, SW_FORCEMINIMIZE );
4603 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4604 todo_wine {
4605 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4606 }
4607 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4608
4609 DestroyWindow(hchild);
4610 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4611 0, 0, 10, 10, hparent, 0, 0, NULL);
4612 flush_sequence();
4613
4614 ShowWindow( hchild, SW_SHOWNA );
4615 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4616 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4617 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4618
4619 /* repeat */
4620 flush_events();
4621 flush_sequence();
4622 ShowWindow( hchild, SW_SHOWNA );
4623 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4624
4625 DestroyWindow(hchild);
4626 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4627 0, 0, 10, 10, hparent, 0, 0, NULL);
4628 flush_sequence();
4629
4630 ShowWindow( hchild, SW_SHOW );
4631 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4632 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4633 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4634
4635 /* repeat */
4636 flush_events();
4637 flush_sequence();
4638 ShowWindow( hchild, SW_SHOW );
4639 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4640
4641 ShowWindow( hchild, SW_HIDE );
4642 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4643 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4644 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4645
4646 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4647 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4648 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4649 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4650
4651 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4652 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4653 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4654 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4655
4656 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4657 flush_sequence();
4658 DestroyWindow(hchild);
4659 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4660
4661 DestroyWindow(hparent);
4662 flush_sequence();
4663 }
4664
4665 /****************** button message test *************************/
4666 static const struct message WmSetFocusButtonSeq[] =
4667 {
4668 { HCBT_SETFOCUS, hook },
4669 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4670 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4671 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4672 { WM_SETFOCUS, sent|wparam, 0 },
4673 { WM_CTLCOLORBTN, sent|defwinproc },
4674 { 0 }
4675 };
4676 static const struct message WmKillFocusButtonSeq[] =
4677 {
4678 { HCBT_SETFOCUS, hook },
4679 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4680 { WM_KILLFOCUS, sent|wparam, 0 },
4681 { WM_CTLCOLORBTN, sent|defwinproc },
4682 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4683 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4684 { 0 }
4685 };
4686 static const struct message WmSetFocusStaticSeq[] =
4687 {
4688 { HCBT_SETFOCUS, hook },
4689 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4690 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4691 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4692 { WM_SETFOCUS, sent|wparam, 0 },
4693 { WM_CTLCOLORSTATIC, sent|defwinproc },
4694 { 0 }
4695 };
4696 static const struct message WmKillFocusStaticSeq[] =
4697 {
4698 { HCBT_SETFOCUS, hook },
4699 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4700 { WM_KILLFOCUS, sent|wparam, 0 },
4701 { WM_CTLCOLORSTATIC, sent|defwinproc },
4702 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4703 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4704 { 0 }
4705 };
4706 static const struct message WmLButtonDownSeq[] =
4707 {
4708 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4709 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4710 { HCBT_SETFOCUS, hook },
4711 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4712 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4713 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4714 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4715 { WM_CTLCOLORBTN, sent|defwinproc },
4716 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4717 { WM_CTLCOLORBTN, sent|defwinproc },
4718 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4719 { 0 }
4720 };
4721 static const struct message WmLButtonUpSeq[] =
4722 {
4723 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4724 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4725 { WM_CTLCOLORBTN, sent|defwinproc },
4726 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4727 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4728 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4729 { 0 }
4730 };
4731 static const struct message WmSetFontButtonSeq[] =
4732 {
4733 { WM_SETFONT, sent },
4734 { WM_PAINT, sent },
4735 { WM_ERASEBKGND, sent|defwinproc|optional },
4736 { WM_CTLCOLORBTN, sent|defwinproc },
4737 { 0 }
4738 };
4739
4740 static WNDPROC old_button_proc;
4741
4742 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4743 {
4744 static long defwndproc_counter = 0;
4745 LRESULT ret;
4746 struct message msg;
4747
4748 trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4749
4750 /* explicitly ignore WM_GETICON message */
4751 if (message == WM_GETICON) return 0;
4752
4753 msg.message = message;
4754 msg.flags = sent|wparam|lparam;
4755 if (defwndproc_counter) msg.flags |= defwinproc;
4756 msg.wParam = wParam;
4757 msg.lParam = lParam;
4758 add_message(&msg);
4759
4760 if (message == BM_SETSTATE)
4761 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4762
4763 defwndproc_counter++;
4764 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4765 defwndproc_counter--;
4766
4767 return ret;
4768 }
4769
4770 static void subclass_button(void)
4771 {
4772 WNDCLASSA cls;
4773
4774 if (!GetClassInfoA(0, "button", &cls)) assert(0);
4775
4776 old_button_proc = cls.lpfnWndProc;
4777
4778 cls.hInstance = GetModuleHandle(0);
4779 cls.lpfnWndProc = button_hook_proc;
4780 cls.lpszClassName = "my_button_class";
4781 UnregisterClass(cls.lpszClassName, cls.hInstance);
4782 if (!RegisterClassA(&cls)) assert(0);
4783 }
4784
4785 static void test_button_messages(void)
4786 {
4787 static const struct
4788 {
4789 DWORD style;
4790 DWORD dlg_code;
4791 const struct message *setfocus;
4792 const struct message *killfocus;
4793 } button[] = {
4794 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4795 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4796 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4797 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4798 { BS_CHECKBOX, DLGC_BUTTON,
4799 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4800 { BS_AUTOCHECKBOX, DLGC_BUTTON,
4801 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4802 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4803 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4804 { BS_3STATE, DLGC_BUTTON,
4805 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4806 { BS_AUTO3STATE, DLGC_BUTTON,
4807 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4808 { BS_GROUPBOX, DLGC_STATIC,
4809 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4810 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4811 WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4812 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4813 WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4814 { BS_OWNERDRAW, DLGC_BUTTON,
4815 WmSetFocusButtonSeq, WmKillFocusButtonSeq }
4816 };
4817 unsigned int i;
4818 HWND hwnd;
4819 DWORD dlg_code;
4820 HFONT zfont;
4821
4822 subclass_button();
4823
4824 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
4825 {
4826 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
4827 0, 0, 50, 14, 0, 0, 0, NULL);
4828 ok(hwnd != 0, "Failed to create button window\n");
4829
4830 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4831 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4832
4833 ShowWindow(hwnd, SW_SHOW);
4834 UpdateWindow(hwnd);
4835 SetFocus(0);
4836 flush_sequence();
4837
4838 trace("button style %08x\n", button[i].style);
4839 SetFocus(hwnd);
4840 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
4841
4842 SetFocus(0);
4843 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
4844
4845 DestroyWindow(hwnd);
4846 }
4847
4848 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
4849 0, 0, 50, 14, 0, 0, 0, NULL);
4850 ok(hwnd != 0, "Failed to create button window\n");
4851
4852 SetFocus(0);
4853 flush_events();
4854 flush_sequence();
4855
4856 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
4857 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
4858
4859 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
4860 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
4861
4862 flush_sequence();
4863 zfont = (HFONT)GetStockObject(SYSTEM_FONT);
4864 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
4865 UpdateWindow(hwnd);
4866 ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
4867
4868 DestroyWindow(hwnd);
4869 }
4870
4871 /****************** static message test *************************/
4872 static const struct message WmSetFontStaticSeq[] =
4873 {
4874 { WM_SETFONT, sent },
4875 { WM_PAINT, sent|defwinproc },
4876 { WM_ERASEBKGND, sent|defwinproc|optional },
4877 { WM_CTLCOLORSTATIC, sent|defwinproc },
4878 { 0 }
4879 };
4880
4881 static WNDPROC old_static_proc;
4882
4883 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4884 {
4885 static long defwndproc_counter = 0;
4886 LRESULT ret;
4887 struct message msg;
4888
4889 trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4890
4891 /* explicitly ignore WM_GETICON message */
4892 if (message == WM_GETICON) return 0;
4893
4894 msg.message = message;
4895 msg.flags = sent|wparam|lparam;
4896 if (defwndproc_counter) msg.flags |= defwinproc;
4897 msg.wParam = wParam;
4898 msg.lParam = lParam;
4899 add_message(&msg);
4900
4901 defwndproc_counter++;
4902 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
4903 defwndproc_counter--;
4904
4905 return ret;
4906 }
4907
4908 static void subclass_static(void)
4909 {
4910 WNDCLASSA cls;
4911
4912 if (!GetClassInfoA(0, "static", &cls)) assert(0);
4913
4914 old_static_proc = cls.lpfnWndProc;
4915
4916 cls.hInstance = GetModuleHandle(0);
4917 cls.lpfnWndProc = static_hook_proc;
4918 cls.lpszClassName = "my_static_class";
4919 UnregisterClass(cls.lpszClassName, cls.hInstance);
4920 if (!RegisterClassA(&cls)) assert(0);
4921 }
4922
4923 static void test_static_messages(void)
4924 {
4925 /* FIXME: make as comprehensive as the button message test */
4926 static const struct
4927 {
4928 DWORD style;
4929 DWORD dlg_code;
4930 const struct message *setfont;
4931 } static_ctrl[] = {
4932 { SS_LEFT, DLGC_STATIC,
4933 WmSetFontStaticSeq }
4934 };
4935 unsigned int i;
4936 HWND hwnd;
4937 DWORD dlg_code;
4938
4939 subclass_static();
4940
4941 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
4942 {
4943 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
4944 0, 0, 50, 14, 0, 0, 0, NULL);
4945 ok(hwnd != 0, "Failed to create static window\n");
4946
4947 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4948 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4949
4950 ShowWindow(hwnd, SW_SHOW);
4951 UpdateWindow(hwnd);
4952 SetFocus(0);
4953 flush_sequence();
4954
4955 trace("static style %08x\n", static_ctrl[i].style);
4956 SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
4957 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
4958
4959 DestroyWindow(hwnd);
4960 }
4961 }
4962
4963 /****************** ComboBox message test *************************/
4964 #define ID_COMBOBOX 0x000f
4965
4966 static const struct message WmKeyDownComboSeq[] =
4967 {
4968 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
4969 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
4970 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
4971 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
4972 { WM_CTLCOLOREDIT, sent|parent },
4973 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
4974 { 0 }
4975 };
4976
4977 static WNDPROC old_combobox_proc;
4978
4979 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4980 {
4981 static long defwndproc_counter = 0;
4982 LRESULT ret;
4983 struct message msg;
4984
4985 /* do not log painting messages */
4986 if (message != WM_PAINT &&
4987 message != WM_NCPAINT &&
4988 message != WM_SYNCPAINT &&
4989 message != WM_ERASEBKGND &&
4990 message != WM_NCHITTEST &&
4991 message != WM_GETTEXT &&
4992 message != WM_GETICON &&
4993 message != WM_DEVICECHANGE)
4994 {
4995 trace("combo: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4996
4997 msg.message = message;
4998 msg.flags = sent|wparam|lparam;
4999 if (defwndproc_counter) msg.flags |= defwinproc;
5000 msg.wParam = wParam;
5001 msg.lParam = lParam;
5002 add_message(&msg);
5003 }
5004
5005 defwndproc_counter++;
5006 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5007 defwndproc_counter--;
5008
5009 return ret;
5010 }
5011
5012 static void subclass_combobox(void)
5013 {
5014 WNDCLASSA cls;
5015
5016 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5017
5018 old_combobox_proc = cls.lpfnWndProc;
5019
5020 cls.hInstance = GetModuleHandle(0);
5021 cls.lpfnWndProc = combobox_hook_proc;
5022 cls.lpszClassName = "my_combobox_class";
5023 UnregisterClass(cls.lpszClassName, cls.hInstance);
5024 if (!RegisterClassA(&cls)) assert(0);
5025 }
5026
5027 static void test_combobox_messages(void)
5028 {
5029 HWND parent, combo;
5030 LRESULT ret;
5031
5032 subclass_combobox();
5033
5034 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5035 100, 100, 200, 200, 0, 0, 0, NULL);
5036 ok(parent != 0, "Failed to create parent window\n");
5037 flush_sequence();
5038
5039 combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5040 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5041 ok(combo != 0, "Failed to create combobox window\n");
5042
5043 UpdateWindow(combo);
5044
5045 ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5046 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5047
5048 ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5049 ok(ret == 0, "expected 0, got %ld\n", ret);
5050 ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5051 ok(ret == 1, "expected 1, got %ld\n", ret);
5052 ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5053 ok(ret == 2, "expected 2, got %ld\n", ret);
5054
5055 SendMessage(combo, CB_SETCURSEL, 0, 0);
5056 SetFocus(combo);
5057 flush_sequence();
5058
5059 log_all_parent_messages++;
5060 SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5061 SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5062 log_all_parent_messages--;
5063 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5064
5065 DestroyWindow(combo);
5066 DestroyWindow(parent);
5067 }
5068
5069 /****************** WM_IME_KEYDOWN message test *******************/
5070
5071 static const struct message WmImeKeydownMsgSeq_0[] =
5072 {
5073 { WM_IME_KEYDOWN, wparam, VK_RETURN },
5074 { WM_CHAR, wparam, 'A' },
5075 { 0 }
5076 };
5077
5078 static const struct message WmImeKeydownMsgSeq_1[] =
5079 {
5080 { WM_KEYDOWN, wparam, VK_RETURN },
5081 { WM_CHAR, wparam, VK_RETURN },
5082 { 0 }
5083 };
5084
5085 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5086 {
5087 struct message msg;
5088
5089 trace("wmime_keydown_procA: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5090
5091 msg.message = message;
5092 msg.flags = wparam|lparam;
5093 msg.wParam = wParam;
5094 msg.lParam = lParam;
5095 add_message(&msg);
5096
5097 return DefWindowProcA(hwnd, message, wParam, lParam);
5098 }
5099
5100 static void register_wmime_keydown_class(void)
5101 {
5102 WNDCLASSA cls;
5103
5104 ZeroMemory(&cls, sizeof(WNDCLASSA));
5105 cls.lpfnWndProc = wmime_keydown_procA;
5106 cls.hInstance = GetModuleHandleA(0);
5107 cls.lpszClassName = "wmime_keydown_class";
5108 if (!RegisterClassA(&cls)) assert(0);
5109 }
5110
5111 void test_wmime_keydown_message(void)
5112 {
5113 HWND hwnd;
5114 MSG msg;
5115
5116 trace("Message sequences by WM_IME_KEYDOWN\n");
5117
5118 register_wmime_keydown_class();
5119 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5120 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5121 NULL, NULL, 0);
5122 flush_events();
5123 flush_sequence();
5124
5125 SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5126 SendMessage(hwnd, WM_CHAR, 'A', 1);
5127 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5128
5129 while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5130 {
5131 TranslateMessage(&msg);
5132 DispatchMessage(&msg);
5133 }
5134 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5135
5136 DestroyWindow(hwnd);
5137 }
5138
5139 /************* painting message test ********************/
5140
5141 void dump_region(HRGN hrgn)
5142 {
5143 DWORD i, size;
5144 RGNDATA *data = NULL;
5145 RECT *rect;
5146
5147 if (!hrgn)
5148 {
5149 printf( "null region\n" );
5150 return;
5151 }
5152 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5153 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5154 GetRegionData( hrgn, size, data );
5155 printf("%d rects:", data->rdh.nCount );
5156 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5157 printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5158 printf("\n");
5159 HeapFree( GetProcessHeap(), 0, data );
5160 }
5161
5162 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5163 {
5164 INT ret;
5165 RECT r1, r2;
5166 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5167 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5168
5169 ret = GetUpdateRgn( hwnd, update, FALSE );
5170 ok( ret != ERROR, "GetUpdateRgn failed\n" );
5171 if (ret == NULLREGION)
5172 {
5173 ok( !hrgn, "Update region shouldn't be empty\n" );
5174 }
5175 else
5176 {
5177 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5178 {
5179 ok( 0, "Regions are different\n" );
5180 if (winetest_debug > 0)
5181 {
5182 printf( "Update region: " );
5183 dump_region( update );
5184 printf( "Wanted region: " );
5185 dump_region( hrgn );
5186 }
5187 }
5188 }
5189 GetRgnBox( update, &r1 );
5190 GetUpdateRect( hwnd, &r2, FALSE );
5191 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5192 "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5193 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5194
5195 DeleteObject( tmp );
5196 DeleteObject( update );
5197 }
5198
5199 static const struct message WmInvalidateRgn[] = {
5200 { WM_NCPAINT, sent },
5201 { WM_GETTEXT, sent|defwinproc|optional },
5202 { 0 }
5203 };
5204
5205 static const struct message WmGetUpdateRect[] = {
5206 { WM_NCPAINT, sent },
5207 { WM_GETTEXT, sent|defwinproc|optional },
5208 { WM_PAINT, sent },
5209 { 0 }
5210 };
5211
5212 static const struct message WmInvalidateFull[] = {
5213 { WM_NCPAINT, sent|wparam, 1 },
5214 { WM_GETTEXT, sent|defwinproc|optional },
5215 { 0 }
5216 };
5217
5218 static const struct message WmInvalidateErase[] = {
5219 { WM_NCPAINT, sent|wparam, 1 },
5220 { WM_GETTEXT, sent|defwinproc|optional },
5221 { WM_ERASEBKGND, sent },
5222 { 0 }
5223 };
5224
5225 static const struct message WmInvalidatePaint[] = {
5226 { WM_PAINT, sent },
5227 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5228 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5229 { 0 }
5230 };
5231
5232 static const struct message WmInvalidateErasePaint[] = {
5233 { WM_PAINT, sent },
5234 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5235 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5236 { WM_ERASEBKGND, sent|beginpaint },
5237 { 0 }
5238 };
5239
5240 static const struct message WmInvalidateErasePaint2[] = {
5241 { WM_PAINT, sent },
5242 { WM_NCPAINT, sent|beginpaint },
5243 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5244 { WM_ERASEBKGND, sent|beginpaint },
5245 { 0 }
5246 };
5247
5248 static const struct message WmErase[] = {
5249 { WM_ERASEBKGND, sent },
5250 { 0 }
5251 };
5252
5253 static const struct message WmPaint[] = {
5254 { WM_PAINT, sent },
5255 { 0 }
5256 };
5257
5258 static const struct message WmParentOnlyPaint[] = {
5259 { WM_PAINT, sent|parent },
5260 { 0 }
5261 };
5262
5263 static const struct message WmInvalidateParent[] = {
5264 { WM_NCPAINT, sent|parent },
5265 { WM_GETTEXT, sent|defwinproc|parent|optional },
5266 { WM_ERASEBKGND, sent|parent },
5267 { 0 }
5268 };
5269
5270 static const struct message WmInvalidateParentChild[] = {
5271 { WM_NCPAINT, sent|parent },
5272 { WM_GETTEXT, sent|defwinproc|parent|optional },
5273 { WM_ERASEBKGND, sent|parent },
5274 { WM_NCPAINT, sent },
5275 { WM_GETTEXT, sent|defwinproc|optional },
5276 { WM_ERASEBKGND, sent },
5277 { 0 }
5278 };
5279
5280 static const struct message WmInvalidateParentChild2[] = {
5281 { WM_ERASEBKGND, sent|parent },
5282 { WM_NCPAINT, sent },
5283 { WM_GETTEXT, sent|defwinproc|optional },
5284 { WM_ERASEBKGND, sent },
5285 { 0 }
5286 };
5287
5288 static const struct message WmParentPaint[] = {
5289 { WM_PAINT, sent|parent },
5290 { WM_PAINT, sent },
5291 { 0 }
5292 };
5293
5294 static const struct message WmParentPaintNc[] = {
5295 { WM_PAINT, sent|parent },
5296 { WM_PAINT, sent },
5297 { WM_NCPAINT, sent|beginpaint },
5298 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5299 { WM_ERASEBKGND, sent|beginpaint },
5300 { 0 }
5301 };
5302
5303 static const struct message WmChildPaintNc[] = {
5304 { WM_PAINT, sent },
5305 { WM_NCPAINT, sent|beginpaint },
5306 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5307 { WM_ERASEBKGND, sent|beginpaint },
5308 { 0 }
5309 };
5310
5311 static const struct message WmParentErasePaint[] = {
5312 { WM_PAINT, sent|parent },
5313 { WM_NCPAINT, sent|parent|beginpaint },
5314 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5315 { WM_ERASEBKGND, sent|parent|beginpaint },
5316 { WM_PAINT, sent },
5317 { WM_NCPAINT, sent|beginpaint },
5318 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5319 { WM_ERASEBKGND, sent|beginpaint },
5320 { 0 }
5321 };
5322
5323 static const struct message WmParentOnlyNcPaint[] = {
5324 { WM_PAINT, sent|parent },
5325 { WM_NCPAINT, sent|parent|beginpaint },
5326 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5327 { 0 }
5328 };
5329
5330 static const struct message WmSetParentStyle[] = {
5331 { WM_STYLECHANGING, sent|parent },
5332 { WM_STYLECHANGED, sent|parent },
5333 { 0 }
5334 };
5335
5336 static void test_paint_messages(void)
5337 {
5338 BOOL ret;
5339 RECT rect;
5340 POINT pt;
5341 MSG msg;
5342 HWND hparent, hchild;
5343 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5344 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5345 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5346 100, 100, 200, 200, 0, 0, 0, NULL);
5347 ok (hwnd != 0, "Failed to create overlapped window\n");
5348
5349 ShowWindow( hwnd, SW_SHOW );
5350 UpdateWindow( hwnd );
5351 flush_events();
5352 flush_sequence();
5353
5354 check_update_rgn( hwnd, 0 );
5355 SetRectRgn( hrgn, 10, 10, 20, 20 );
5356 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5357 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5358 check_update_rgn( hwnd, hrgn );
5359 SetRectRgn( hrgn2, 20, 20, 30, 30 );
5360 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5361 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5362 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5363 check_update_rgn( hwnd, hrgn );
5364 /* validate everything */
5365 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5366 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5367 check_update_rgn( hwnd, 0 );
5368
5369 /* test empty region */
5370 SetRectRgn( hrgn, 10, 10, 10, 15 );
5371 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5372 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5373 check_update_rgn( hwnd, 0 );
5374 /* test empty rect */
5375 SetRect( &rect, 10, 10, 10, 15 );
5376 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5377 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5378 check_update_rgn( hwnd, 0 );
5379
5380 /* flush pending messages */
5381 flush_events();
5382 flush_sequence();
5383
5384 GetClientRect( hwnd, &rect );
5385 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5386 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5387 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5388 */
5389 trace("testing InvalidateRect(0, NULL, FALSE)\n");
5390 SetRectEmpty( &rect );
5391 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5392 check_update_rgn( hwnd, hrgn );
5393 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5394 flush_events();
5395 ok_sequence( WmPaint, "Paint", FALSE );
5396 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5397 check_update_rgn( hwnd, 0 );
5398
5399 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5400 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5401 */
5402 trace("testing ValidateRect(0, NULL)\n");
5403 SetRectEmpty( &rect );
5404 ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
5405 check_update_rgn( hwnd, hrgn );
5406 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5407 flush_events();
5408 ok_sequence( WmPaint, "Paint", FALSE );
5409 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5410 check_update_rgn( hwnd, 0 );
5411
5412 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5413 SetLastError(0xdeadbeef);
5414 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5415 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5416 "wrong error code %d\n", GetLastError());
5417 check_update_rgn( hwnd, 0 );
5418 flush_events();
5419 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5420
5421 trace("testing ValidateRgn(0, NULL)\n");
5422 SetLastError(0xdeadbeef);
5423 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5424 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
5425 check_update_rgn( hwnd, 0 );
5426 flush_events();
5427 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5428
5429 /* now with frame */
5430 SetRectRgn( hrgn, -5, -5, 20, 20 );
5431
5432 /* flush pending messages */
5433 flush_events();
5434 flush_sequence();
5435 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5436 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5437
5438 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
5439 check_update_rgn( hwnd, hrgn );
5440
5441 flush_sequence();
5442 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5443 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5444
5445 flush_sequence();
5446 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5447 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5448
5449 GetClientRect( hwnd, &rect );
5450 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5451 check_update_rgn( hwnd, hrgn );
5452
5453 flush_sequence();
5454 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5455 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5456
5457 flush_sequence();
5458 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5459 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5460 check_update_rgn( hwnd, 0 );
5461
5462 flush_sequence();
5463 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5464 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5465 check_update_rgn( hwnd, 0 );
5466
5467 flush_sequence();
5468 SetRectRgn( hrgn, 0, 0, 100, 100 );
5469 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5470 SetRectRgn( hrgn, 0, 0, 50, 100 );
5471 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5472 SetRectRgn( hrgn, 50, 0, 100, 100 );
5473 check_update_rgn( hwnd, hrgn );
5474 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5475 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
5476 check_update_rgn( hwnd, 0 );
5477
5478 flush_sequence();
5479 SetRectRgn( hrgn, 0, 0, 100, 100 );
5480 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5481 SetRectRgn( hrgn, 0, 0, 100, 50 );
5482 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5483 ok_sequence( WmErase, "Erase", FALSE );
5484 SetRectRgn( hrgn, 0, 50, 100, 100 );
5485 check_update_rgn( hwnd, hrgn );
5486
5487 flush_sequence();
5488 SetRectRgn( hrgn, 0, 0, 100, 100 );
5489 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5490 SetRectRgn( hrgn, 0, 0, 50, 50 );
5491 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5492 ok_sequence( WmPaint, "Paint", FALSE );
5493
5494 flush_sequence();
5495 SetRectRgn( hrgn, -4, -4, -2, -2 );
5496 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5497 SetRectRgn( hrgn, -200, -200, -198, -198 );
5498 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5499 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5500
5501 flush_sequence();
5502 SetRectRgn( hrgn, -4, -4, -2, -2 );
5503 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5504 SetRectRgn( hrgn, -4, -4, -3, -3 );
5505 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5506 SetRectRgn( hrgn, 0, 0, 1, 1 );
5507 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5508 ok_sequence( WmPaint, "Paint", FALSE );
5509
5510 flush_sequence();
5511 SetRectRgn( hrgn, -4, -4, -1, -1 );
5512 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5513 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5514 /* make sure no WM_PAINT was generated */
5515 flush_events();
5516 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5517
5518 flush_sequence();
5519 SetRectRgn( hrgn, -4, -4, -1, -1 );
5520 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5521 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5522 {
5523 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5524 {
5525 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5526 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5527 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5528 ret = GetUpdateRect( hwnd, &rect, FALSE );
5529 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5530 /* this will send WM_NCPAINT and validate the non client area */
5531 ret = GetUpdateRect( hwnd, &rect, TRUE );
5532 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5533 }
5534 DispatchMessage( &msg );
5535 }
5536 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5537
5538 DestroyWindow( hwnd );
5539
5540 /* now test with a child window */
5541
5542 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5543 100, 100, 200, 200, 0, 0, 0, NULL);
5544 ok (hparent != 0, "Failed to create parent window\n");
5545
5546 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5547 10, 10, 100, 100, hparent, 0, 0, NULL);
5548 ok (hchild != 0, "Failed to create child window\n");
5549
5550 ShowWindow( hparent, SW_SHOW );
5551 UpdateWindow( hparent );
5552 UpdateWindow( hchild );
5553 flush_events();
5554 flush_sequence();
5555 log_all_parent_messages++;
5556
5557 SetRect( &rect, 0, 0, 50, 50 );
5558 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5559 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5560 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5561
5562 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5563 pt.x = pt.y = 0;
5564 MapWindowPoints( hchild, hparent, &pt, 1 );
5565 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5566 check_update_rgn( hchild, hrgn );
5567 SetRectRgn( hrgn, 0, 0, 50, 50 );
5568 check_update_rgn( hparent, hrgn );
5569 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5570 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5571 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5572 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5573
5574 flush_events();
5575 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5576
5577 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5578 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5579 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5580 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5581 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5582
5583 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5584 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5585 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5586
5587 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5588 flush_sequence();
5589 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5590 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5591 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5592
5593 /* flush all paint messages */
5594 flush_events();
5595 flush_sequence();
5596
5597 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5598 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5599 SetRectRgn( hrgn, 0, 0, 50, 50 );
5600 check_update_rgn( hparent, hrgn );
5601 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5602 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5603 SetRectRgn( hrgn, 0, 0, 50, 50 );
5604 check_update_rgn( hparent, hrgn );
5605
5606 /* flush all paint messages */
5607 flush_events();
5608 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5609 flush_sequence();
5610
5611 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5612 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5613 SetRectRgn( hrgn, 0, 0, 50, 50 );
5614 check_update_rgn( hparent, hrgn );
5615 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5616 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5617 SetRectRgn( hrgn2, 10, 10, 50, 50 );
5618 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5619 check_update_rgn( hparent, hrgn );
5620 /* flush all paint messages */
5621 flush_events();
5622 flush_sequence();
5623
5624 /* same as above but parent gets completely validated */
5625 SetRect( &rect, 20, 20, 30, 30 );
5626 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5627 SetRectRgn( hrgn, 20, 20, 30, 30 );
5628 check_update_rgn( hparent, hrgn );
5629 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5630 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5631 check_update_rgn( hparent, 0 ); /* no update region */
5632 flush_events();
5633 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
5634
5635 /* make sure RDW_VALIDATE on child doesn't have the same effect */
5636 flush_sequence();
5637 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5638 SetRectRgn( hrgn, 20, 20, 30, 30 );
5639 check_update_rgn( hparent, hrgn );
5640 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5641 SetRectRgn( hrgn, 20, 20, 30, 30 );
5642 check_update_rgn( hparent, hrgn );
5643
5644 /* same as above but normal WM_PAINT doesn't validate parent */
5645 flush_sequence();
5646 SetRect( &rect, 20, 20, 30, 30 );
5647 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5648 SetRectRgn( hrgn, 20, 20, 30, 30 );
5649 check_update_rgn( hparent, hrgn );
5650 /* no WM_PAINT in child while parent still pending */
5651 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5652 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5653 while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5654 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5655
5656 flush_sequence();
5657 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5658 /* no WM_PAINT in child while parent still pending */
5659 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5660 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5661 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5662 /* now that parent is valid child should get WM_PAINT */
5663 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5664 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5665 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5666 ok_sequence( WmEmptySeq, "No other message", FALSE );
5667
5668 /* same thing with WS_CLIPCHILDREN in parent */
5669 flush_sequence();
5670 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5671 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5672 /* changing style invalidates non client area, but we need to invalidate something else to see it */
5673 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5674 ok_sequence( WmEmptySeq, "No message", FALSE );
5675 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5676 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5677
5678 flush_sequence();
5679 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5680 SetRectRgn( hrgn, 20, 20, 30, 30 );
5681 check_update_rgn( hparent, hrgn );
5682 /* no WM_PAINT in child while parent still pending */
5683 while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5684 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5685 /* WM_PAINT in parent first */
5686 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5687 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5688
5689 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5690 flush_sequence();
5691 SetRect( &rect, 0, 0, 30, 30 );
5692 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5693 SetRectRgn( hrgn, 0, 0, 30, 30 );
5694 check_update_rgn( hparent, hrgn );
5695 flush_events();
5696 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5697
5698 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5699 flush_sequence();
5700 SetRect( &rect, -10, 0, 30, 30 );
5701 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5702 SetRect( &rect, 0, 0, 20, 20 );
5703 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5704 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5705 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5706
5707 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5708 flush_sequence();
5709 SetRect( &rect, -10, 0, 30, 30 );
5710 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5711 SetRect( &rect, 0, 0, 100, 100 );
5712 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5713 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5714 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5715 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5716 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5717
5718 /* test RDW_INTERNALPAINT behavior */
5719
5720 flush_sequence();
5721 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5722 flush_events();
5723 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5724
5725 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5726 flush_events();
5727 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5728
5729 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5730 flush_events();
5731 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5732
5733 assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5734 UpdateWindow( hparent );
5735 flush_events();
5736 flush_sequence();
5737 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5738 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5739 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5740 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5741 flush_events();
5742 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5743
5744 UpdateWindow( hparent );
5745 flush_events();
5746 flush_sequence();
5747 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5748 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5749 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5750 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5751 flush_events();
5752 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5753
5754 SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5755 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5756 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5757 flush_events();
5758 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5759
5760 assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5761 UpdateWindow( hparent );
5762 flush_events();
5763 flush_sequence();
5764 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5765 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5766 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5767 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5768 flush_events();
5769 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5770
5771 UpdateWindow( hparent );
5772 flush_events();
5773 flush_sequence();
5774 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5775 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5776 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5777 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5778 flush_events();
5779 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5780
5781 log_all_parent_messages--;
5782 DestroyWindow( hparent );
5783 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5784
5785 DeleteObject( hrgn );
5786 DeleteObject( hrgn2 );
5787 }
5788
5789 struct wnd_event
5790 {
5791 HWND hwnd;
5792 HANDLE event;
5793 };
5794
5795 static DWORD WINAPI thread_proc(void *param)
5796 {
5797 MSG msg;
5798 struct wnd_event *wnd_event = (struct wnd_event *)param;
5799
5800 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
5801 100, 100, 200, 200, 0, 0, 0, NULL);
5802 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
5803
5804 SetEvent(wnd_event->event);
5805
5806 while (GetMessage(&msg, 0, 0, 0))
5807 {
5808 TranslateMessage(&msg);
5809 DispatchMessage(&msg);
5810 }
5811
5812 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
5813
5814 return 0;
5815 }
5816
5817 static void test_interthread_messages(void)
5818 {
5819 HANDLE hThread;
5820 DWORD tid;
5821 WNDPROC proc;
5822 MSG msg;
5823 char buf[256];
5824 int len, expected_len;
5825 struct wnd_event wnd_event;
5826 BOOL ret;
5827
5828 wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
5829 if (!wnd_event.event)
5830 {
5831 trace("skipping interthread message test under win9x\n");
5832 return;
5833 }
5834
5835 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
5836 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
5837
5838 ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5839
5840 CloseHandle(wnd_event.event);
5841
5842 SetLastError(0xdeadbeef);
5843 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
5844 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
5845 "wrong error code %d\n", GetLastError());
5846
5847 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5848 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
5849
5850 expected_len = lstrlenA("window caption text");
5851 memset(buf, 0, sizeof(buf));
5852 SetLastError(0xdeadbeef);
5853 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
5854 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
5855 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
5856
5857 msg.hwnd = wnd_event.hwnd;
5858 msg.message = WM_GETTEXT;
5859 msg.wParam = sizeof(buf);
5860 msg.lParam = (LPARAM)buf;
5861 memset(buf, 0, sizeof(buf));
5862 SetLastError(0xdeadbeef);
5863 len = DispatchMessageA(&msg);
5864 ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
5865 "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
5866
5867 /* the following test causes an exception in user.exe under win9x */
5868 msg.hwnd = wnd_event.hwnd;
5869 msg.message = WM_TIMER;
5870 msg.wParam = 0;
5871 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5872 SetLastError(0xdeadbeef);
5873 len = DispatchMessageA(&msg);
5874 ok(!len && GetLastError() == 0xdeadbeef,
5875 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
5876
5877 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
5878 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
5879
5880 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5881 CloseHandle(hThread);
5882
5883 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
5884 }
5885
5886
5887 static const struct message WmVkN[] = {
5888 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5889 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5890 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5891 { WM_CHAR, wparam|lparam, 'n', 1 },
5892 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
5893 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5894 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5895 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5896 { 0 }
5897 };
5898 static const struct message WmShiftVkN[] = {
5899 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5900 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5901 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5902 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5903 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5904 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5905 { WM_CHAR, wparam|lparam, 'N', 1 },
5906 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
5907 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5908 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5909 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5910 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5911 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5912 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5913 { 0 }
5914 };
5915 static const struct message WmCtrlVkN[] = {
5916 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5917 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5918 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5919 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5920 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5921 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5922 { WM_CHAR, wparam|lparam, 0x000e, 1 },
5923 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5924 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5925 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5926 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5927 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5928 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5929 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5930 { 0 }
5931 };
5932 static const struct message WmCtrlVkN_2[] = {
5933 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5934 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5935 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5936 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5937 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5938 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5939 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5940 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5941 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5942 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5943 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5944 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5945 { 0 }
5946 };
5947 static const struct message WmAltVkN[] = {
5948 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5949 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5950 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5951 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5952 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5953 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5954 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
5955 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
5956 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
5957 { HCBT_SYSCOMMAND, hook },
5958 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5959 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5960 { 0x00AE, sent|defwinproc|optional }, /* XP */
5961 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
5962 { WM_INITMENU, sent|defwinproc },
5963 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5964 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
5965 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5966 { WM_CAPTURECHANGED, sent|defwinproc },
5967 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
5968 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5969 { WM_EXITMENULOOP, sent|defwinproc },
5970 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
5971 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
5972 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5973 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5974 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5975 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5976 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5977 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5978 { 0 }
5979 };
5980 static const struct message WmAltVkN_2[] = {
5981 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5982 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5983 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5984 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5985 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5986 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
5987 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5988 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5989 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5990 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5991 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5992 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5993 { 0 }
5994 };
5995 static const struct message WmCtrlAltVkN[] = {
5996 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5997 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5998 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5999 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6000 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6001 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6002 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6003 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6004 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6005 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6006 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6007 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6008 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6009 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6010 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6011 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6012 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6013 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6014 { 0 }
6015 };
6016 static const struct message WmCtrlShiftVkN[] = {
6017 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6018 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6019 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6020 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6021 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6022 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6023 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6024 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6025 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6026 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6027 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6028 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6029 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6030 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6031 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6032 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6033 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6034 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6035 { 0 }
6036 };
6037 static const struct message WmCtrlAltShiftVkN[] = {
6038 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6039 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6040 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6041 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6042 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6043 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6044 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6045 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6046 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6047 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6048 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6049 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6050 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6051 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6052 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6053 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6054 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6055 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6056 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6057 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6058 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6059 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6060 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6061 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6062 { 0 }
6063 };
6064 static const struct message WmAltPressRelease[] = {
6065 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6066 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6067 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6068 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6069 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6070 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6071 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6072 { HCBT_SYSCOMMAND, hook },
6073 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6074 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6075 { WM_INITMENU, sent|defwinproc },
6076 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6077 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6078 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6079
6080 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6081
6082 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6083 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6084 { WM_CAPTURECHANGED, sent|defwinproc },
6085 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6086 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6087 { WM_EXITMENULOOP, sent|defwinproc },
6088 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6089 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6090 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6091 { 0 }
6092 };
6093 static const struct message WmAltMouseButton[] = {
6094 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6095 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6096 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6097 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6098 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6099 { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
6100 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
6101 { WM_LBUTTONUP, wparam, 0, 0 },
6102 { WM_LBUTTONUP, sent|wparam, 0, 0 },
6103 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6104 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6105 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6106 { 0 }
6107 };
6108 static const struct message WmF1Seq[] = {
6109 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6110 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6111 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6112 { WM_KEYF1, wparam|lparam, 0, 0 },
6113 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6114 { WM_HELP, sent|defwinproc },
6115 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6116 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6117 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6118 { 0 }
6119 };
6120 static const struct message WmVkAppsSeq[] = {
6121 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6122 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6123 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6124 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6125 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6126 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6127 { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6128 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6129 { 0 }
6130 };
6131
6132 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6133 {
6134 MSG msg;
6135
6136 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6137 {
6138 struct message log_msg;
6139
6140 trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
6141
6142 /* ignore some unwanted messages */
6143 if (msg.message == WM_MOUSEMOVE ||
6144 msg.message == WM_GETICON ||
6145 msg.message == WM_DEVICECHANGE)
6146 continue;
6147
6148 log_msg.message = msg.message;
6149 log_msg.flags = wparam|lparam;
6150 log_msg.wParam = msg.wParam;
6151 log_msg.lParam = msg.lParam;
6152 add_message(&log_msg);
6153
6154 if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6155 {
6156 TranslateMessage(&msg);
6157 DispatchMessage(&msg);
6158 }
6159 }
6160 }
6161
6162 static void test_accelerators(void)
6163 {
6164 RECT rc;
6165 SHORT state;
6166 HACCEL hAccel;
6167 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6168 100, 100, 200, 200, 0, 0, 0, NULL);
6169 BOOL ret;
6170
6171 assert(hwnd != 0);
6172 UpdateWindow(hwnd);
6173 flush_events();
6174 flush_sequence();
6175
6176 SetFocus(hwnd);
6177 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6178
6179 state = GetKeyState(VK_SHIFT);
6180 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6181 state = GetKeyState(VK_CAPITAL);
6182 ok(state == 0, "wrong CapsLock state %04x\n", state);
6183
6184 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6185 assert(hAccel != 0);
6186
6187 pump_msg_loop(hwnd, 0);
6188 flush_sequence();
6189
6190 trace("testing VK_N press/release\n");
6191 flush_sequence();
6192 keybd_event('N', 0, 0, 0);
6193 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6194 pump_msg_loop(hwnd, hAccel);
6195 ok_sequence(WmVkN, "VK_N press/release", FALSE);
6196
6197 trace("testing Shift+VK_N press/release\n");
6198 flush_sequence();
6199 keybd_event(VK_SHIFT, 0, 0, 0);
6200 keybd_event('N', 0, 0, 0);
6201 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6202 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6203 pump_msg_loop(hwnd, hAccel);
6204 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6205
6206 trace("testing Ctrl+VK_N press/release\n");
6207 flush_sequence();
6208 keybd_event(VK_CONTROL, 0, 0, 0);
6209 keybd_event('N', 0, 0, 0);
6210 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6211 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6212 pump_msg_loop(hwnd, hAccel);
6213 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6214
6215 trace("testing Alt+VK_N press/release\n");
6216 flush_sequence();
6217 keybd_event(VK_MENU, 0, 0, 0);
6218 keybd_event('N', 0, 0, 0);
6219 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6220 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6221 pump_msg_loop(hwnd, hAccel);
6222 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6223
6224 trace("testing Ctrl+Alt+VK_N press/release 1\n");
6225 flush_sequence();
6226 keybd_event(VK_CONTROL, 0, 0, 0);
6227 keybd_event(VK_MENU, 0, 0, 0);
6228 keybd_event('N', 0, 0, 0);
6229 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6230 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6231 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6232 pump_msg_loop(hwnd, hAccel);
6233 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6234
6235 ret = DestroyAcceleratorTable(hAccel);
6236 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6237
6238 hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6239 assert(hAccel != 0);
6240
6241 trace("testing VK_N press/release\n");
6242 flush_sequence();
6243 keybd_event('N', 0, 0, 0);
6244 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6245 pump_msg_loop(hwnd, hAccel);
6246 ok_sequence(WmVkN, "VK_N press/release", FALSE);
6247
6248 trace("testing Shift+VK_N press/release\n");
6249 flush_sequence();
6250 keybd_event(VK_SHIFT, 0, 0, 0);
6251 keybd_event('N', 0, 0, 0);
6252 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6253 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6254 pump_msg_loop(hwnd, hAccel);
6255 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6256
6257 trace("testing Ctrl+VK_N press/release 2\n");
6258 flush_sequence();
6259 keybd_event(VK_CONTROL, 0, 0, 0);
6260 keybd_event('N', 0, 0, 0);
6261 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6262 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6263 pump_msg_loop(hwnd, hAccel);
6264 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6265
6266 trace("testing Alt+VK_N press/release 2\n");
6267 flush_sequence();
6268 keybd_event(VK_MENU, 0, 0, 0);
6269 keybd_event('N', 0, 0, 0);
6270 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6271 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6272 pump_msg_loop(hwnd, hAccel);
6273 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6274
6275 trace("testing Ctrl+Alt+VK_N press/release 2\n");
6276 flush_sequence();
6277 keybd_event(VK_CONTROL, 0, 0, 0);
6278 keybd_event(VK_MENU, 0, 0, 0);
6279 keybd_event('N', 0, 0, 0);
6280 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6281 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6282 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6283 pump_msg_loop(hwnd, hAccel);
6284 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6285
6286 trace("testing Ctrl+Shift+VK_N press/release\n");
6287 flush_sequence();
6288 keybd_event(VK_CONTROL, 0, 0, 0);
6289 keybd_event(VK_SHIFT, 0, 0, 0);
6290 keybd_event('N', 0, 0, 0);
6291 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6292 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6293 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6294 pump_msg_loop(hwnd, hAccel);
6295 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6296
6297 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6298 flush_sequence();
6299 keybd_event(VK_CONTROL, 0, 0, 0);
6300 keybd_event(VK_MENU, 0, 0, 0);
6301 keybd_event(VK_SHIFT, 0, 0, 0);
6302 keybd_event('N', 0, 0, 0);
6303 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6304 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6305 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6306 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6307 pump_msg_loop(hwnd, hAccel);
6308 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6309
6310 ret = DestroyAcceleratorTable(hAccel);
6311 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6312
6313 trace("testing Alt press/release\n");
6314 flush_sequence();
6315 keybd_event(VK_MENU, 0, 0, 0);
6316 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6317 keybd_event(VK_MENU, 0, 0, 0);
6318 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6319 pump_msg_loop(hwnd, 0);
6320 /* this test doesn't pass in Wine for managed windows */
6321 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6322
6323 trace("testing Alt+MouseButton press/release\n");
6324 /* first, move mouse pointer inside of the window client area */
6325 GetClientRect(hwnd, &rc);
6326 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6327 rc.left += (rc.right - rc.left)/2;
6328 rc.top += (rc.bottom - rc.top)/2;
6329 SetCursorPos(rc.left, rc.top);
6330
6331 flush_events();
6332 flush_sequence();
6333 keybd_event(VK_MENU, 0, 0, 0);
6334 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6335 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6336 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6337 pump_msg_loop(hwnd, 0);
6338 ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
6339
6340 trace("testing VK_F1 press/release\n");
6341 keybd_event(VK_F1, 0, 0, 0);
6342 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6343 pump_msg_loop(hwnd, 0);
6344 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
6345
6346 trace("testing VK_APPS press/release\n");
6347 keybd_event(VK_APPS, 0, 0, 0);
6348 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6349 pump_msg_loop(hwnd, 0);
6350 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6351
6352 DestroyWindow(hwnd);
6353 }
6354
6355 /************* window procedures ********************/
6356
6357 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
6358 WPARAM wParam, LPARAM lParam)
6359 {
6360 static long defwndproc_counter = 0;
6361 static long beginpaint_counter = 0;
6362 LRESULT ret;
6363 struct message msg;
6364
6365 trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6366
6367 /* explicitly ignore WM_GETICON message */
6368 if (message == WM_GETICON) return 0;
6369
6370 switch (message)
6371 {
6372 case WM_ENABLE:
6373 {
6374 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6375 ok((BOOL)wParam == !(style & WS_DISABLED),
6376 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6377 break;
6378 }
6379
6380 case WM_CAPTURECHANGED:
6381 if (test_DestroyWindow_flag)
6382 {
6383 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6384 if (style & WS_CHILD)
6385 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6386 else if (style & WS_POPUP)
6387 lParam = WND_POPUP_ID;
6388 else
6389 lParam = WND_PARENT_ID;
6390 }
6391 break;
6392
6393 case WM_NCDESTROY:
6394 {
6395 HWND capture;
6396
6397 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6398 capture = GetCapture();
6399 if (capture)
6400 {
6401 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6402 trace("current capture %p, releasing...\n", capture);
6403 ReleaseCapture();
6404 }
6405 }
6406 /* fall through */
6407 case WM_DESTROY:
6408 if (pGetAncestor)
6409 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6410 if (test_DestroyWindow_flag)
6411 {
6412 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6413 if (style & WS_CHILD)
6414 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6415 else if (style & WS_POPUP)
6416 lParam = WND_POPUP_ID;
6417 else
6418 lParam = WND_PARENT_ID;
6419 }
6420 break;
6421
6422 /* test_accelerators() depends on this */
6423 case WM_NCHITTEST:
6424 return HTCLIENT;
6425
6426 /* ignore */
6427 case WM_MOUSEMOVE:
6428 case WM_SETCURSOR:
6429 case WM_DEVICECHANGE:
6430 return 0;
6431
6432 case WM_WINDOWPOSCHANGING:
6433 case WM_WINDOWPOSCHANGED:
6434 {
6435 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6436
6437 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6438 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6439 winpos->hwnd, winpos->hwndInsertAfter,
6440 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6441 dump_winpos_flags(winpos->flags);
6442
6443 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6444 * in the high word for internal purposes
6445 */
6446 wParam = winpos->flags & 0xffff;
6447 /* We are not interested in the flags that don't match under XP and Win9x */
6448 wParam &= ~(SWP_NOZORDER);
6449 break;
6450 }
6451 }
6452
6453 msg.message = message;
6454 msg.flags = sent|wparam|lparam;
6455 if (defwndproc_counter) msg.flags |= defwinproc;
6456 if (beginpaint_counter) msg.flags |= beginpaint;
6457 msg.wParam = wParam;
6458 msg.lParam = lParam;
6459 add_message(&msg);
6460
6461 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6462 {
6463 HWND parent = GetParent(hwnd);
6464 RECT rc;
6465 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6466
6467 GetClientRect(parent, &rc);
6468 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6469
6470 trace("ptReserved = (%d,%d)\n"
6471 "ptMaxSize = (%d,%d)\n"
6472 "ptMaxPosition = (%d,%d)\n"
6473 "ptMinTrackSize = (%d,%d)\n"
6474 "ptMaxTrackSize = (%d,%d)\n",
6475 minmax->ptReserved.x, minmax->ptReserved.y,
6476 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6477 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6478 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6479 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6480
6481 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6482 minmax->ptMaxSize.x, rc.right);
6483 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6484 minmax->ptMaxSize.y, rc.bottom);
6485 }
6486
6487 if (message == WM_PAINT)
6488 {
6489 PAINTSTRUCT ps;
6490 beginpaint_counter++;
6491 BeginPaint( hwnd, &ps );
6492 beginpaint_counter--;
6493 EndPaint( hwnd, &ps );
6494 return 0;
6495 }
6496
6497 defwndproc_counter++;
6498 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
6499 : DefWindowProcA(hwnd, message, wParam, lParam);
6500 defwndproc_counter--;
6501
6502 return ret;
6503 }
6504
6505 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6506 {
6507 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6508 }
6509
6510 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6511 {
6512 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6513 }
6514
6515 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6516 {
6517 static long defwndproc_counter = 0;
6518 LRESULT ret;
6519 struct message msg;
6520
6521 trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6522
6523 /* explicitly ignore WM_GETICON message */
6524 if (message == WM_GETICON) return 0;
6525
6526 msg.message = message;
6527 msg.flags = sent|wparam|lparam;
6528 if (defwndproc_counter) msg.flags |= defwinproc;
6529 msg.wParam = wParam;
6530 msg.lParam = lParam;
6531 add_message(&msg);
6532
6533 if (message == WM_CREATE)
6534 {
6535 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6536 SetWindowLongA(hwnd, GWL_STYLE, style);
6537 }
6538
6539 defwndproc_counter++;
6540 ret = DefWindowProcA(hwnd, message, wParam, lParam);
6541 defwndproc_counter--;
6542
6543 return ret;
6544 }
6545
6546 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6547 {
6548 static long defwndproc_counter = 0;
6549 static long beginpaint_counter = 0;
6550 LRESULT ret;
6551 struct message msg;
6552 LPARAM logged_lParam;
6553
6554 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6555
6556 /* explicitly ignore WM_GETICON message */
6557 if (message == WM_GETICON) return 0;
6558
6559 logged_lParam=lParam;
6560 if (log_all_parent_messages ||
6561 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
6562 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
6563 message == WM_ENABLE || message == WM_ENTERIDLE ||
6564 message == WM_DRAWITEM ||
6565 message == WM_IME_SETCONTEXT)
6566 {
6567 switch (message)
6568 {
6569 /* ignore */
6570 case WM_NCHITTEST:
6571 return HTCLIENT;
6572 case WM_SETCURSOR:
6573 case WM_MOUSEMOVE:
6574 return 0;
6575
6576 case WM_ERASEBKGND:
6577 {
6578 RECT rc;
6579 INT ret = GetClipBox((HDC)wParam, &rc);
6580
6581 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
6582 ret, rc.left, rc.top, rc.right, rc.bottom);
6583 break;
6584 }
6585
6586 case WM_WINDOWPOSCHANGING:
6587 case WM_WINDOWPOSCHANGED:
6588 {
6589 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6590
6591 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6592 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6593 winpos->hwnd, winpos->hwndInsertAfter,
6594 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6595 dump_winpos_flags(winpos->flags);
6596
6597 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6598 * in the high word for internal purposes
6599 */
6600 wParam = winpos->flags & 0xffff;
6601 /* We are not interested in the flags that don't match under XP and Win9x */
6602 wParam &= ~(SWP_NOZORDER);
6603 break;
6604 }
6605
6606 case WM_DRAWITEM:
6607 {
6608 /* encode DRAWITEMSTRUCT into an LPARAM */
6609 DRAW_ITEM_STRUCT di;
6610 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
6611
6612 trace("WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x\n",
6613 dis->CtlType, dis->CtlID, dis->itemID, dis->itemAction, dis->itemState);
6614
6615 di.u.item.type = dis->CtlType;
6616 di.u.item.ctl_id = dis->CtlID;
6617 di.u.item.item_id = dis->itemID;
6618 di.u.item.action = dis->itemAction;
6619 di.u.item.state = dis->itemState;
6620
6621 logged_lParam = di.u.lp;
6622 break;
6623 }
6624 }
6625
6626 msg.message = message;
6627 msg.flags = sent|parent|wparam|lparam;
6628 if (defwndproc_counter) msg.flags |= defwinproc;
6629 if (beginpaint_counter) msg.flags |= beginpaint;
6630 msg.wParam = wParam;
6631 msg.lParam = logged_lParam;
6632 add_message(&msg);
6633 }
6634
6635 if (message == WM_PAINT)
6636 {
6637 PAINTSTRUCT ps;
6638 beginpaint_counter++;
6639 BeginPaint( hwnd, &ps );
6640 beginpaint_counter--;
6641 EndPaint( hwnd, &ps );
6642 return 0;
6643 }
6644
6645 defwndproc_counter++;
6646 ret = DefWindowProcA(hwnd, message, wParam, lParam);
6647 defwndproc_counter--;
6648
6649 return ret;
6650 }
6651
6652 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6653 {
6654 static long defwndproc_counter = 0;
6655 LRESULT ret;
6656 struct message msg;
6657
6658 trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6659
6660 /* explicitly ignore WM_GETICON message */
6661 if (message == WM_GETICON) return 0;
6662
6663 if (test_def_id)
6664 {
6665 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6666 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6667 if (after_end_dialog)
6668 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6669 else
6670 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6671 }
6672
6673 switch (message)
6674 {
6675 case WM_WINDOWPOSCHANGING:
6676 case WM_WINDOWPOSCHANGED:
6677 {
6678 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6679
6680 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6681 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6682 winpos->hwnd, winpos->hwndInsertAfter,
6683 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6684 dump_winpos_flags(winpos->flags);
6685
6686 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6687 * in the high word for internal purposes
6688 */
6689 wParam = winpos->flags & 0xffff;
6690 /* We are not interested in the flags that don't match under XP and Win9x */
6691 wParam &= ~(SWP_NOZORDER);
6692 break;
6693 }
6694 }
6695
6696 msg.message = message;
6697 msg.flags = sent|wparam|lparam;
6698 if (defwndproc_counter) msg.flags |= defwinproc;
6699 msg.wParam = wParam;
6700 msg.lParam = lParam;
6701 add_message(&msg);
6702
6703 defwndproc_counter++;
6704 ret = DefDlgProcA(hwnd, message, wParam, lParam);
6705 defwndproc_counter--;
6706
6707 return ret;
6708 }
6709
6710 static void dump_winpos_flags(UINT flags)
6711 {
6712 if (!winetest_debug) return;
6713
6714 if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
6715 if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
6716 if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
6717 if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
6718 if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
6719 if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
6720 if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
6721 if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
6722 if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
6723 if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
6724 if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
6725 if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
6726 if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
6727 if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
6728 if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
6729
6730 #define DUMPED_FLAGS \
6731 (SWP_NOSIZE | \
6732 SWP_NOMOVE | \
6733 SWP_NOZORDER | \
6734 SWP_NOREDRAW | \
6735 SWP_NOACTIVATE | \
6736 SWP_FRAMECHANGED | \
6737 SWP_SHOWWINDOW | \
6738 SWP_HIDEWINDOW | \
6739 SWP_NOCOPYBITS | \
6740 SWP_NOOWNERZORDER | \
6741 SWP_NOSENDCHANGING | \
6742 SWP_DEFERERASE | \
6743 SWP_ASYNCWINDOWPOS | \
6744 SWP_NOCLIENTSIZE | \
6745 SWP_NOCLIENTMOVE)
6746
6747 if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
6748 printf("\n");
6749 #undef DUMPED_FLAGS
6750 }
6751
6752 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6753 {
6754 static long defwndproc_counter = 0;
6755 LRESULT ret;
6756 struct message msg;
6757
6758 /* log only specific messages we are interested in */
6759 switch (message)
6760 {
6761 #if 0 /* probably log these as well */
6762 case WM_ACTIVATE:
6763 case WM_SETFOCUS:
6764 case WM_KILLFOCUS:
6765 #endif
6766 case WM_SHOWWINDOW:
6767 trace("WM_SHOWWINDOW %ld\n", wParam);
6768 break;
6769 case WM_SIZE:
6770 trace("WM_SIZE %ld\n", wParam);
6771 break;
6772 case WM_MOVE:
6773 trace("WM_MOVE\n");
6774 break;
6775 case WM_GETMINMAXINFO:
6776 trace("WM_GETMINMAXINFO\n");
6777 break;
6778
6779 case WM_WINDOWPOSCHANGING:
6780 case WM_WINDOWPOSCHANGED:
6781 {
6782 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6783
6784 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6785 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6786 winpos->hwnd, winpos->hwndInsertAfter,
6787 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6788 trace("flags: ");
6789 dump_winpos_flags(winpos->flags);
6790
6791 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6792 * in the high word for internal purposes
6793 */
6794 wParam = winpos->flags & 0xffff;
6795 /* We are not interested in the flags that don't match under XP and Win9x */
6796 wParam &= ~(SWP_NOZORDER);
6797 break;
6798 }
6799
6800 default: /* ignore */
6801 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
6802 return DefWindowProcA(hwnd, message, wParam, lParam);
6803 }
6804
6805 msg.message = message;
6806 msg.flags = sent|wparam|lparam;
6807 if (defwndproc_counter) msg.flags |= defwinproc;
6808 msg.wParam = wParam;
6809 msg.lParam = lParam;
6810 add_message(&msg);
6811
6812 defwndproc_counter++;
6813 ret = DefWindowProcA(hwnd, message, wParam, lParam);
6814 defwndproc_counter--;
6815
6816 return ret;
6817 }
6818
6819 static BOOL RegisterWindowClasses(void)
6820 {
6821 WNDCLASSA cls;
6822 WNDCLASSW clsW;
6823
6824 cls.style = 0;
6825 cls.lpfnWndProc = MsgCheckProcA;
6826 cls.cbClsExtra = 0;
6827 cls.cbWndExtra = 0;
6828 cls.hInstance = GetModuleHandleA(0);
6829 cls.hIcon = 0;
6830 cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
6831 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6832 cls.lpszMenuName = NULL;
6833 cls.lpszClassName = "TestWindowClass";
6834 if(!RegisterClassA(&cls)) return FALSE;
6835
6836 cls.lpfnWndProc = ShowWindowProcA;
6837 cls.lpszClassName = "ShowWindowClass";
6838 if(!RegisterClassA(&cls)) return FALSE;
6839
6840 cls.lpfnWndProc = PopupMsgCheckProcA;
6841 cls.lpszClassName = "TestPopupClass";
6842 if(!RegisterClassA(&cls)) return FALSE;
6843
6844 cls.lpfnWndProc = ParentMsgCheckProcA;
6845 cls.lpszClassName = "TestParentClass";
6846 if(!RegisterClassA(&cls)) return FALSE;
6847
6848 cls.lpfnWndProc = DefWindowProcA;
6849 cls.lpszClassName = "SimpleWindowClass";
6850 if(!RegisterClassA(&cls)) return FALSE;
6851
6852 cls.style = CS_NOCLOSE;
6853 cls.lpszClassName = "NoCloseWindowClass";
6854 if(!RegisterClassA(&cls)) return FALSE;
6855
6856 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
6857 cls.style = 0;
6858 cls.hInstance = GetModuleHandleA(0);
6859 cls.hbrBackground = 0;
6860 cls.lpfnWndProc = TestDlgProcA;
6861 cls.lpszClassName = "TestDialogClass";
6862 if(!RegisterClassA(&cls)) return FALSE;
6863
6864 clsW.style = 0;
6865 clsW.lpfnWndProc = MsgCheckProcW;
6866 clsW.cbClsExtra = 0;
6867 clsW.cbWndExtra = 0;
6868 clsW.hInstance = GetModuleHandleW(0);
6869 clsW.hIcon = 0;
6870 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
6871 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
6872 clsW.lpszMenuName = NULL;
6873 clsW.lpszClassName = testWindowClassW;
6874 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
6875
6876 return TRUE;
6877 }
6878
6879 static HHOOK hCBT_hook;
6880 static DWORD cbt_hook_thread_id;
6881
6882 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
6883 {
6884 static const char * const CBT_code_name[10] = {
6885 "HCBT_MOVESIZE",
6886 "HCBT_MINMAX",
6887 "HCBT_QS",
6888 "HCBT_CREATEWND",
6889 "HCBT_DESTROYWND",
6890 "HCBT_ACTIVATE",
6891 "HCBT_CLICKSKIPPED",
6892 "HCBT_KEYSKIPPED",
6893 "HCBT_SYSCOMMAND",
6894 "HCBT_SETFOCUS" };
6895 const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
6896 HWND hwnd;
6897 char buf[256];
6898
6899 trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
6900
6901 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6902
6903 if (nCode == HCBT_CLICKSKIPPED)
6904 {
6905 /* ignore this event, XP sends it a lot when switching focus between windows */
6906 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6907 }
6908
6909 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
6910 {
6911 struct message msg;
6912
6913 msg.message = nCode;
6914 msg.flags = hook|wparam|lparam;
6915 msg.wParam = wParam;
6916 msg.lParam = lParam;
6917 add_message(&msg);
6918
6919 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6920 }
6921
6922 if (nCode == HCBT_DESTROYWND)
6923 {
6924 if (test_DestroyWindow_flag)
6925 {
6926 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
6927 if (style & WS_CHILD)
6928 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
6929 else if (style & WS_POPUP)
6930 lParam = WND_POPUP_ID;
6931 else
6932 lParam = WND_PARENT_ID;
6933 }
6934 }
6935
6936 /* Log also SetFocus(0) calls */
6937 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6938
6939 if (GetClassNameA(hwnd, buf, sizeof(buf)))
6940 {
6941 if (!lstrcmpiA(buf, "TestWindowClass") ||
6942 !lstrcmpiA(buf, "ShowWindowClass") ||
6943 !lstrcmpiA(buf, "TestParentClass") ||
6944 !lstrcmpiA(buf, "TestPopupClass") ||
6945 !lstrcmpiA(buf, "SimpleWindowClass") ||
6946 !lstrcmpiA(buf, "TestDialogClass") ||
6947 !lstrcmpiA(buf, "MDI_frame_class") ||
6948 !lstrcmpiA(buf, "MDI_client_class") ||
6949 !lstrcmpiA(buf, "MDI_child_class") ||
6950 !lstrcmpiA(buf, "my_button_class") ||
6951 !lstrcmpiA(buf, "my_edit_class") ||
6952 !lstrcmpiA(buf, "static") ||
6953 !lstrcmpiA(buf, "ListBox") ||
6954 !lstrcmpiA(buf, "ComboBox") ||
6955 !lstrcmpiA(buf, "MyDialogClass") ||
6956 !lstrcmpiA(buf, "#32770"))
6957 {
6958 struct message msg;
6959
6960 msg.message = nCode;
6961 msg.flags = hook|wparam|lparam;
6962 msg.wParam = wParam;
6963 msg.lParam = lParam;
6964 add_message(&msg);
6965 }
6966 }
6967 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6968 }
6969
6970 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
6971 DWORD event,
6972 HWND hwnd,
6973 LONG object_id,
6974 LONG child_id,
6975 DWORD thread_id,
6976 DWORD event_time)
6977 {
6978 char buf[256];
6979
6980 trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6981 hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6982
6983 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6984
6985 /* ignore mouse cursor events */
6986 if (object_id == OBJID_CURSOR) return;
6987
6988 if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
6989 {
6990 if (!hwnd ||
6991 !lstrcmpiA(buf, "TestWindowClass") ||
6992 !lstrcmpiA(buf, "TestParentClass") ||
6993 !lstrcmpiA(buf, "TestPopupClass") ||
6994 !lstrcmpiA(buf, "SimpleWindowClass") ||
6995 !lstrcmpiA(buf, "TestDialogClass") ||
6996 !lstrcmpiA(buf, "MDI_frame_class") ||
6997 !lstrcmpiA(buf, "MDI_client_class") ||
6998 !lstrcmpiA(buf, "MDI_child_class") ||
6999 !lstrcmpiA(buf, "my_button_class") ||
7000 !lstrcmpiA(buf, "my_edit_class") ||
7001 !lstrcmpiA(buf, "static") ||
7002 !lstrcmpiA(buf, "ListBox") ||
7003 !lstrcmpiA(buf, "ComboBox") ||
7004 !lstrcmpiA(buf, "MyDialogClass") ||
7005 !lstrcmpiA(buf, "#32770"))
7006 {
7007 struct message msg;
7008
7009 msg.message = event;
7010 msg.flags = winevent_hook|wparam|lparam;
7011 msg.wParam = object_id;
7012 msg.lParam = child_id;
7013 add_message(&msg);
7014 }
7015 }
7016 }
7017
7018 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7019 static const WCHAR wszAnsi[] = {'U',0};
7020
7021 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7022 {
7023 switch (uMsg)
7024 {
7025 case CB_FINDSTRINGEXACT:
7026 trace("String: %p\n", (LPCWSTR)lParam);
7027 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7028 return 1;
7029 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7030 return 0;
7031 return -1;
7032 }
7033 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7034 }
7035
7036 static const struct message WmGetTextLengthAfromW[] = {
7037 { WM_GETTEXTLENGTH, sent },
7038 { WM_GETTEXT, sent },
7039 { 0 }
7040 };
7041
7042 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7043
7044 /* dummy window proc for WM_GETTEXTLENGTH test */
7045 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7046 {
7047 switch(msg)
7048 {
7049 case WM_GETTEXTLENGTH:
7050 return lstrlenW(dummy_window_text) + 37; /* some random length */
7051 case WM_GETTEXT:
7052 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7053 return lstrlenW( (LPWSTR)lp );
7054 default:
7055 return DefWindowProcW( hwnd, msg, wp, lp );
7056 }
7057 }
7058
7059 static void test_message_conversion(void)
7060 {
7061 static const WCHAR wszMsgConversionClass[] =
7062 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7063 WNDCLASSW cls;
7064 LRESULT lRes;
7065 HWND hwnd;
7066 WNDPROC wndproc, newproc;
7067 BOOL ret;
7068
7069 cls.style = 0;
7070 cls.lpfnWndProc = MsgConversionProcW;
7071 cls.cbClsExtra = 0;
7072 cls.cbWndExtra = 0;
7073 cls.hInstance = GetModuleHandleW(NULL);
7074 cls.hIcon = NULL;
7075 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7076 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7077 cls.lpszMenuName = NULL;
7078 cls.lpszClassName = wszMsgConversionClass;
7079 /* this call will fail on Win9x, but that doesn't matter as this test is
7080 * meaningless on those platforms */
7081 if(!RegisterClassW(&cls)) return;
7082
7083 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7084 100, 100, 200, 200, 0, 0, 0, NULL);
7085 ok(hwnd != NULL, "Window creation failed\n");
7086
7087 /* {W, A} -> A */
7088
7089 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7090 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7091 ok(lRes == 0, "String should have been converted\n");
7092 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7093 ok(lRes == 1, "String shouldn't have been converted\n");
7094
7095 /* {W, A} -> W */
7096
7097 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7098 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7099 ok(lRes == 1, "String shouldn't have been converted\n");
7100 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7101 ok(lRes == 1, "String shouldn't have been converted\n");
7102
7103 /* Synchronous messages */
7104
7105 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7106 ok(lRes == 0, "String should have been converted\n");
7107 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7108 ok(lRes == 1, "String shouldn't have been converted\n");
7109
7110 /* Asynchronous messages */
7111
7112 SetLastError(0);
7113 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7114 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7115 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7116 SetLastError(0);
7117 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7118 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7119 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7120 SetLastError(0);
7121 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7122 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7123 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7124 SetLastError(0);
7125 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7126 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7127 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7128 SetLastError(0);
7129 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7130 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7131 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7132 SetLastError(0);
7133 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7134 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7135 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7136 SetLastError(0);
7137 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7138 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7139 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7140 SetLastError(0);
7141 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7142 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7143 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7144
7145 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7146
7147 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7148 WS_OVERLAPPEDWINDOW,
7149 100, 100, 200, 200, 0, 0, 0, NULL);
7150 assert(hwnd);
7151 flush_sequence();
7152 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7153 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7154 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7155 "got bad length %ld\n", lRes );
7156
7157 flush_sequence();
7158 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7159 hwnd, WM_GETTEXTLENGTH, 0, 0);
7160 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7161 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7162 "got bad length %ld\n", lRes );
7163
7164 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7165 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7166 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7167 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7168 NULL, 0, NULL, NULL ),
7169 "got bad length %ld\n", lRes );
7170
7171 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
7172 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7173 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7174 NULL, 0, NULL, NULL ),
7175 "got bad length %ld\n", lRes );
7176
7177 ret = DestroyWindow(hwnd);
7178 ok( ret, "DestroyWindow() error %d\n", GetLastError());
7179 }
7180
7181 struct timer_info
7182 {
7183 HWND hWnd;
7184 HANDLE handles[2];
7185 DWORD id;
7186 };
7187
7188 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7189 {
7190 }
7191
7192 #define TIMER_ID 0x19
7193
7194 static DWORD WINAPI timer_thread_proc(LPVOID x)
7195 {
7196 struct timer_info *info = x;
7197 DWORD r;
7198
7199 r = KillTimer(info->hWnd, 0x19);
7200 ok(r,"KillTimer failed in thread\n");
7201 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7202 ok(r,"SetTimer failed in thread\n");
7203 ok(r==TIMER_ID,"SetTimer id different\n");
7204 r = SetEvent(info->handles[0]);
7205 ok(r,"SetEvent failed in thread\n");
7206 return 0;
7207 }
7208
7209 static void test_timers(void)
7210 {
7211 struct timer_info info;
7212 DWORD id;
7213
7214 info.hWnd = CreateWindow ("TestWindowClass", NULL,
7215 WS_OVERLAPPEDWINDOW ,
7216 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7217 NULL, NULL, 0);
7218
7219 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7220 ok(info.id, "SetTimer failed\n");
7221 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7222 info.handles[0] = CreateEvent(NULL,0,0,NULL);
7223 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7224
7225 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7226
7227 WaitForSingleObject(info.handles[1], INFINITE);
7228
7229 CloseHandle(info.handles[0]);
7230 CloseHandle(info.handles[1]);
7231
7232 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7233
7234 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7235 }
7236
7237 static int count = 0;
7238 static VOID CALLBACK callback_count(
7239 HWND hwnd,
7240 UINT uMsg,
7241 UINT_PTR idEvent,
7242 DWORD dwTime
7243 )
7244 {
7245 count++;
7246 }
7247
7248 static void test_timers_no_wnd(void)
7249 {
7250 UINT_PTR id, id2;
7251 MSG msg;
7252
7253 count = 0;
7254 id = SetTimer(NULL, 0, 100, callback_count);
7255 ok(id != 0, "did not get id from SetTimer.\n");
7256 id2 = SetTimer(NULL, id, 200, callback_count);
7257 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7258 Sleep(150);
7259 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7260 ok(count == 0, "did not get zero count as expected (%i).\n", count);
7261 Sleep(150);
7262 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7263 ok(count == 1, "did not get one count as expected (%i).\n", count);
7264 KillTimer(NULL, id);
7265 Sleep(250);
7266 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7267 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7268 }
7269
7270 /* Various win events with arbitrary parameters */
7271 static const struct message WmWinEventsSeq[] = {
7272 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7273 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7274 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7275 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7276 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7277 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7278 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7279 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7280 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7281 /* our win event hook ignores OBJID_CURSOR events */
7282 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7283 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7284 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7285 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7286 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7287 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7288 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7289 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7290 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7291 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7292 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7293 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7294 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7295 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7296 { 0 }
7297 };
7298 static const struct message WmWinEventCaretSeq[] = {
7299 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7300 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7301 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7302 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7303 { 0 }
7304 };
7305 static const struct message WmWinEventCaretSeq_2[] = {
7306 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7307 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7308 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7309 { 0 }
7310 };
7311 static const struct message WmWinEventAlertSeq[] = {
7312 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7313 { 0 }
7314 };
7315 static const struct message WmWinEventAlertSeq_2[] = {
7316 /* create window in the thread proc */
7317 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7318 /* our test event */
7319 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7320 { 0 }
7321 };
7322 static const struct message WmGlobalHookSeq_1[] = {
7323 /* create window in the thread proc */
7324 { HCBT_CREATEWND, hook|lparam, 0, 2 },
7325 /* our test events */
7326 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7327 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7328 { 0 }
7329 };
7330 static const struct message WmGlobalHookSeq_2[] = {
7331 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7332 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7333 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7334 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7335 { 0 }
7336 };
7337
7338 static const struct message WmMouseLLHookSeq[] = {
7339 { WM_MOUSEMOVE, hook },
7340 { WM_LBUTTONUP, hook },
7341 { WM_MOUSEMOVE, hook },
7342 { 0 }
7343 };
7344
7345 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7346 DWORD event,
7347 HWND hwnd,
7348 LONG object_id,
7349 LONG child_id,
7350 DWORD thread_id,
7351 DWORD event_time)
7352 {
7353 char buf[256];
7354
7355 trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7356 hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7357
7358 if (GetClassNameA(hwnd, buf, sizeof(buf)))
7359 {
7360 if (!lstrcmpiA(buf, "TestWindowClass") ||
7361 !lstrcmpiA(buf, "static"))
7362 {
7363 struct message msg;
7364
7365 msg.message = event;
7366 msg.flags = winevent_hook|wparam|lparam;
7367 msg.wParam = object_id;
7368 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7369 add_message(&msg);
7370 }
7371 }
7372 }
7373
7374 static HHOOK hCBT_global_hook;
7375 static DWORD cbt_global_hook_thread_id;
7376
7377 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
7378 {
7379 HWND hwnd;
7380 char buf[256];
7381
7382 trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam);
7383
7384 if (nCode == HCBT_SYSCOMMAND)
7385 {
7386 struct message msg;
7387
7388 msg.message = nCode;
7389 msg.flags = hook|wparam|lparam;
7390 msg.wParam = wParam;
7391 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7392 add_message(&msg);
7393
7394 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7395 }
7396 /* WH_MOUSE_LL hook */
7397 if (nCode == HC_ACTION)
7398 {
7399 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7400
7401 /* we can't test for real mouse events */
7402 if (mhll->flags & LLMHF_INJECTED)
7403 {
7404 struct message msg;
7405
7406 memset (&msg, 0, sizeof (msg));
7407 msg.message = wParam;
7408 msg.flags = hook;
7409 add_message(&msg);
7410 }
7411 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7412 }
7413
7414 /* Log also SetFocus(0) calls */
7415 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7416
7417 if (GetClassNameA(hwnd, buf, sizeof(buf)))
7418 {
7419 if (!lstrcmpiA(buf, "TestWindowClass") ||
7420 !lstrcmpiA(buf, "static"))
7421 {
7422 struct message msg;
7423
7424 msg.message = nCode;
7425 msg.flags = hook|wparam|lparam;
7426 msg.wParam = wParam;
7427 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7428 add_message(&msg);
7429 }
7430 }
7431 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7432 }
7433
7434 static DWORD WINAPI win_event_global_thread_proc(void *param)
7435 {
7436 HWND hwnd;
7437 MSG msg;
7438 HANDLE hevent = *(HANDLE *)param;
7439
7440 assert(pNotifyWinEvent);
7441
7442 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7443 assert(hwnd);
7444 trace("created thread window %p\n", hwnd);
7445
7446 *(HWND *)param = hwnd;
7447
7448 flush_sequence();
7449 /* this event should be received only by our new hook proc,
7450 * an old one does not expect an event from another thread.
7451 */
7452 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7453 SetEvent(hevent);
7454
7455 while (GetMessage(&msg, 0, 0, 0))
7456 {
7457 TranslateMessage(&msg);
7458 DispatchMessage(&msg);
7459 }
7460 return 0;
7461 }
7462
7463 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7464 {
7465 HWND hwnd;
7466 MSG msg;
7467 HANDLE hevent = *(HANDLE *)param;
7468
7469 flush_sequence();
7470 /* these events should be received only by our new hook proc,
7471 * an old one does not expect an event from another thread.
7472 */
7473
7474 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7475 assert(hwnd);
7476 trace("created thread window %p\n", hwnd);
7477
7478 *(HWND *)param = hwnd;
7479
7480 /* Windows doesn't like when a thread plays games with the focus,
7481 that leads to all kinds of misbehaviours and failures to activate
7482 a window. So, better keep next lines commented out.
7483 SetFocus(0);
7484 SetFocus(hwnd);*/
7485
7486 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7487 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7488
7489 SetEvent(hevent);
7490
7491 while (GetMessage(&msg, 0, 0, 0))
7492 {
7493 TranslateMessage(&msg);
7494 DispatchMessage(&msg);
7495 }
7496 return 0;
7497 }
7498
7499 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7500 {
7501 HWND hwnd;
7502 MSG msg;
7503 HANDLE hevent = *(HANDLE *)param;
7504
7505 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7506 assert(hwnd);
7507 trace("created thread window %p\n", hwnd);
7508
7509 *(HWND *)param = hwnd;
7510
7511 flush_sequence();
7512
7513 /* Windows doesn't like when a thread plays games with the focus,
7514 * that leads to all kinds of misbehaviours and failures to activate
7515 * a window. So, better don't generate a mouse click message below.
7516 */
7517 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7518 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7519 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7520
7521 SetEvent(hevent);
7522 while (GetMessage(&msg, 0, 0, 0))
7523 {
7524 TranslateMessage(&msg);
7525 DispatchMessage(&msg);
7526 }
7527 return 0;
7528 }
7529
7530 static void test_winevents(void)
7531 {
7532 BOOL ret;
7533 MSG msg;
7534 HWND hwnd, hwnd2;
7535 UINT i;
7536 HANDLE hthread, hevent;
7537 DWORD tid;
7538 HWINEVENTHOOK hhook;
7539 const struct message *events = WmWinEventsSeq;
7540
7541 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7542 WS_OVERLAPPEDWINDOW,
7543 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7544 NULL, NULL, 0);
7545 assert(hwnd);
7546
7547 /****** start of global hook test *************/
7548 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7549 if (!hCBT_global_hook)
7550 {
7551 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7552 skip( "cannot set global hook\n" );
7553 return;
7554 }
7555
7556 hevent = CreateEventA(NULL, 0, 0, NULL);
7557 assert(hevent);
7558 hwnd2 = (HWND)hevent;
7559
7560 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7561 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7562
7563 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7564
7565 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7566
7567 flush_sequence();
7568 /* this one should be received only by old hook proc */
7569 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7570 /* this one should be received only by old hook proc */
7571 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7572
7573 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7574
7575 ret = UnhookWindowsHookEx(hCBT_global_hook);
7576 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7577
7578 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7579 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7580 CloseHandle(hthread);
7581 CloseHandle(hevent);
7582 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7583 /****** end of global hook test *************/
7584
7585 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7586 {
7587 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7588 return;
7589 }
7590
7591 flush_sequence();
7592
7593 if (0)
7594 {
7595 /* this test doesn't pass under Win9x */
7596 /* win2k ignores events with hwnd == 0 */
7597 SetLastError(0xdeadbeef);
7598 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7599 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7600 GetLastError() == 0xdeadbeef, /* Win9x */
7601 "unexpected error %d\n", GetLastError());
7602 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7603 }
7604
7605 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7606 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7607
7608 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7609
7610 /****** start of event filtering test *************/
7611 hhook = (HWINEVENTHOOK)pSetWinEventHook(
7612 EVENT_OBJECT_SHOW, /* 0x8002 */
7613 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7614 GetModuleHandleA(0), win_event_global_hook_proc,
7615 GetCurrentProcessId(), 0,
7616 WINEVENT_INCONTEXT);
7617 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7618
7619 hevent = CreateEventA(NULL, 0, 0, NULL);
7620 assert(hevent);
7621 hwnd2 = (HWND)hevent;
7622
7623 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7624 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7625
7626 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7627
7628 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7629
7630 flush_sequence();
7631 /* this one should be received only by old hook proc */
7632 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7633 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7634 /* this one should be received only by old hook proc */
7635 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7636
7637 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7638
7639 ret = pUnhookWinEvent(hhook);
7640 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7641
7642 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7643 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7644 CloseHandle(hthread);
7645 CloseHandle(hevent);
7646 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7647 /****** end of event filtering test *************/
7648
7649 /****** start of out of context event test *************/
7650 hhook = (HWINEVENTHOOK)pSetWinEventHook(
7651 EVENT_MIN, EVENT_MAX,
7652 0, win_event_global_hook_proc,
7653 GetCurrentProcessId(), 0,
7654 WINEVENT_OUTOFCONTEXT);
7655 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7656
7657 hevent = CreateEventA(NULL, 0, 0, NULL);
7658 assert(hevent);
7659 hwnd2 = (HWND)hevent;
7660
7661 flush_sequence();
7662
7663 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7664 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7665
7666 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7667
7668 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7669 /* process pending winevent messages */
7670 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7671 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7672
7673 flush_sequence();
7674 /* this one should be received only by old hook proc */
7675 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7676 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7677 /* this one should be received only by old hook proc */
7678 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7679
7680 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7681 /* process pending winevent messages */
7682 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7683 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7684
7685 ret = pUnhookWinEvent(hhook);
7686 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7687
7688 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7689 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7690 CloseHandle(hthread);
7691 CloseHandle(hevent);
7692 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7693 /****** end of out of context event test *************/
7694
7695 /****** start of MOUSE_LL hook test *************/
7696 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7697 /* WH_MOUSE_LL is not supported on Win9x platforms */
7698 if (!hCBT_global_hook)
7699 {
7700 trace("Skipping WH_MOUSE_LL test on this platform\n");
7701 goto skip_mouse_ll_hook_test;
7702 }
7703
7704 hevent = CreateEventA(NULL, 0, 0, NULL);
7705 assert(hevent);
7706 hwnd2 = (HWND)hevent;
7707
7708 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
7709 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7710
7711 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
7712 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7713
7714 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
7715 flush_sequence();
7716
7717 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7718 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7719 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7720
7721 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
7722
7723 ret = UnhookWindowsHookEx(hCBT_global_hook);
7724 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7725
7726 PostThreadMessageA(tid, WM_QUIT, 0, 0);
7727 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7728 CloseHandle(hthread);
7729 CloseHandle(hevent);
7730 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7731 /****** end of MOUSE_LL hook test *************/
7732 skip_mouse_ll_hook_test:
7733
7734 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7735 }
7736
7737 static void test_set_hook(void)
7738 {
7739 BOOL ret;
7740 HHOOK hhook;
7741 HWINEVENTHOOK hwinevent_hook;
7742
7743 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
7744 ok(hhook != 0, "local hook does not require hModule set to 0\n");
7745 UnhookWindowsHookEx(hhook);
7746
7747 if (0)
7748 {
7749 /* this test doesn't pass under Win9x: BUG! */
7750 SetLastError(0xdeadbeef);
7751 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
7752 ok(!hhook, "global hook requires hModule != 0\n");
7753 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
7754 }
7755
7756 SetLastError(0xdeadbeef);
7757 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
7758 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
7759 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
7760 GetLastError() == 0xdeadbeef, /* Win9x */
7761 "unexpected error %d\n", GetLastError());
7762
7763 SetLastError(0xdeadbeef);
7764 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
7765 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
7766 GetLastError() == 0xdeadbeef, /* Win9x */
7767 "unexpected error %d\n", GetLastError());
7768
7769 if (!pSetWinEventHook || !pUnhookWinEvent) return;
7770
7771 /* even process local incontext hooks require hmodule */
7772 SetLastError(0xdeadbeef);
7773 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7774 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
7775 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7776 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7777 GetLastError() == 0xdeadbeef, /* Win9x */
7778 "unexpected error %d\n", GetLastError());
7779
7780 /* even thread local incontext hooks require hmodule */
7781 SetLastError(0xdeadbeef);
7782 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7783 0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
7784 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7785 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7786 GetLastError() == 0xdeadbeef, /* Win9x */
7787 "unexpected error %d\n", GetLastError());
7788
7789 if (0)
7790 {
7791 /* these 3 tests don't pass under Win9x */
7792 SetLastError(0xdeadbeef);
7793 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
7794 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7795 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7796 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7797
7798 SetLastError(0xdeadbeef);
7799 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
7800 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7801 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7802 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7803
7804 SetLastError(0xdeadbeef);
7805 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7806 0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
7807 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
7808 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
7809 }
7810
7811 SetLastError(0xdeadbeef);
7812 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
7813 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7814 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7815 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7816 ret = pUnhookWinEvent(hwinevent_hook);
7817 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7818
7819 todo_wine {
7820 /* This call succeeds under win2k SP4, but fails under Wine.
7821 Does win2k test/use passed process id? */
7822 SetLastError(0xdeadbeef);
7823 hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7824 0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
7825 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7826 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7827 ret = pUnhookWinEvent(hwinevent_hook);
7828 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7829 }
7830
7831 SetLastError(0xdeadbeef);
7832 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
7833 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7834 GetLastError() == 0xdeadbeef, /* Win9x */
7835 "unexpected error %d\n", GetLastError());
7836 }
7837
7838 static const struct message ScrollWindowPaint1[] = {
7839 { WM_PAINT, sent },
7840 { WM_ERASEBKGND, sent|beginpaint },
7841 { 0 }
7842 };
7843
7844 static const struct message ScrollWindowPaint2[] = {
7845 { WM_PAINT, sent },
7846 { 0 }
7847 };
7848
7849 static void test_scrollwindowex(void)
7850 {
7851 HWND hwnd, hchild;
7852 RECT rect={0,0,130,130};
7853
7854 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
7855 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
7856 100, 100, 200, 200, 0, 0, 0, NULL);
7857 ok (hwnd != 0, "Failed to create overlapped window\n");
7858 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
7859 WS_VISIBLE|WS_CAPTION|WS_CHILD,
7860 10, 10, 150, 150, hwnd, 0, 0, NULL);
7861 ok (hchild != 0, "Failed to create child\n");
7862 UpdateWindow(hwnd);
7863 flush_events();
7864 flush_sequence();
7865
7866 /* scroll without the child window */
7867 trace("start scroll\n");
7868 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7869 SW_ERASE|SW_INVALIDATE);
7870 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7871 trace("end scroll\n");
7872 flush_sequence();
7873 flush_events();
7874 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7875 flush_events();
7876 flush_sequence();
7877
7878 /* Now without the SW_ERASE flag */
7879 trace("start scroll\n");
7880 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
7881 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7882 trace("end scroll\n");
7883 flush_sequence();
7884 flush_events();
7885 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
7886 flush_events();
7887 flush_sequence();
7888
7889 /* now scroll the child window as well */
7890 trace("start scroll\n");
7891 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7892 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
7893 todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
7894 /* windows sometimes a WM_MOVE */
7895 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7896 }
7897 trace("end scroll\n");
7898 flush_sequence();
7899 flush_events();
7900 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7901 flush_events();
7902 flush_sequence();
7903
7904 /* now scroll with ScrollWindow() */
7905 trace("start scroll with ScrollWindow\n");
7906 ScrollWindow( hwnd, 5, 5, NULL, NULL);
7907 trace("end scroll\n");
7908 flush_sequence();
7909 flush_events();
7910 ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
7911
7912 ok(DestroyWindow(hchild), "failed to destroy window\n");
7913 ok(DestroyWindow(hwnd), "failed to destroy window\n");
7914 flush_sequence();
7915 }
7916
7917 static const struct message destroy_window_with_children[] = {
7918 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7919 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
7920 { 0x0090, sent|optional },
7921 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
7922 { 0x0090, sent|optional },
7923 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7924 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7925 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7926 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7927 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
7928 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7929 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7930 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7931 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7932 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7933 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7934 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7935 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7936 { 0 }
7937 };
7938
7939 static void test_DestroyWindow(void)
7940 {
7941 BOOL ret;
7942 HWND parent, child1, child2, child3, child4, test;
7943 UINT child_id = WND_CHILD_ID + 1;
7944
7945 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7946 100, 100, 200, 200, 0, 0, 0, NULL);
7947 assert(parent != 0);
7948 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7949 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
7950 assert(child1 != 0);
7951 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7952 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
7953 assert(child2 != 0);
7954 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7955 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
7956 assert(child3 != 0);
7957 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
7958 0, 0, 50, 50, parent, 0, 0, NULL);
7959 assert(child4 != 0);
7960
7961 /* test owner/parent of child2 */
7962 test = GetParent(child2);
7963 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7964 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7965 if(pGetAncestor) {
7966 test = pGetAncestor(child2, GA_PARENT);
7967 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7968 }
7969 test = GetWindow(child2, GW_OWNER);
7970 ok(!test, "wrong owner %p\n", test);
7971
7972 test = SetParent(child2, parent);
7973 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
7974
7975 /* test owner/parent of the parent */
7976 test = GetParent(parent);
7977 ok(!test, "wrong parent %p\n", test);
7978 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
7979 if(pGetAncestor) {
7980 test = pGetAncestor(parent, GA_PARENT);
7981 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7982 }
7983 test = GetWindow(parent, GW_OWNER);
7984 ok(!test, "wrong owner %p\n", test);
7985
7986 /* test owner/parent of child1 */
7987 test = GetParent(child1);
7988 ok(test == parent, "wrong parent %p\n", test);
7989 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
7990 if(pGetAncestor) {
7991 test = pGetAncestor(child1, GA_PARENT);
7992 ok(test == parent, "wrong parent %p\n", test);
7993 }
7994 test = GetWindow(child1, GW_OWNER);
7995 ok(!test, "wrong owner %p\n", test);
7996
7997 /* test owner/parent of child2 */
7998 test = GetParent(child2);
7999 ok(test == parent, "wrong parent %p\n", test);
8000 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8001 if(pGetAncestor) {
8002 test = pGetAncestor(child2, GA_PARENT);
8003 ok(test == parent, "wrong parent %p\n", test);
8004 }
8005 test = GetWindow(child2, GW_OWNER);
8006 ok(!test, "wrong owner %p\n", test);
8007
8008 /* test owner/parent of child3 */
8009 test = GetParent(child3);
8010 ok(test == child1, "wrong parent %p\n", test);
8011 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8012 if(pGetAncestor) {
8013 test = pGetAncestor(child3, GA_PARENT);
8014 ok(test == child1, "wrong parent %p\n", test);
8015 }
8016 test = GetWindow(child3, GW_OWNER);
8017 ok(!test, "wrong owner %p\n", test);
8018
8019 /* test owner/parent of child4 */
8020 test = GetParent(child4);
8021 ok(test == parent, "wrong parent %p\n", test);
8022 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8023 if(pGetAncestor) {
8024 test = pGetAncestor(child4, GA_PARENT);
8025 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8026 }
8027 test = GetWindow(child4, GW_OWNER);
8028 ok(test == parent, "wrong owner %p\n", test);
8029
8030 flush_sequence();
8031
8032 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8033 parent, child1, child2, child3, child4);
8034
8035 SetCapture(child4);
8036 test = GetCapture();
8037 ok(test == child4, "wrong capture window %p\n", test);
8038
8039 test_DestroyWindow_flag = TRUE;
8040 ret = DestroyWindow(parent);
8041 ok( ret, "DestroyWindow() error %d\n", GetLastError());
8042 test_DestroyWindow_flag = FALSE;
8043 ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8044
8045 ok(!IsWindow(parent), "parent still exists\n");
8046 ok(!IsWindow(child1), "child1 still exists\n");
8047 ok(!IsWindow(child2), "child2 still exists\n");
8048 ok(!IsWindow(child3), "child3 still exists\n");
8049 ok(!IsWindow(child4), "child4 still exists\n");
8050
8051 test = GetCapture();
8052 ok(!test, "wrong capture window %p\n", test);
8053 }
8054
8055
8056 static const struct message WmDispatchPaint[] = {
8057 { WM_NCPAINT, sent },
8058 { WM_GETTEXT, sent|defwinproc|optional },
8059 { WM_GETTEXT, sent|defwinproc|optional },
8060 { WM_ERASEBKGND, sent },
8061 { 0 }
8062 };
8063
8064 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8065 {
8066 if (message == WM_PAINT) return 0;
8067 return MsgCheckProcA( hwnd, message, wParam, lParam );
8068 }
8069
8070 static void test_DispatchMessage(void)
8071 {
8072 RECT rect;
8073 MSG msg;
8074 int count;
8075 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8076 100, 100, 200, 200, 0, 0, 0, NULL);
8077 ShowWindow( hwnd, SW_SHOW );
8078 UpdateWindow( hwnd );
8079 flush_events();
8080 flush_sequence();
8081 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8082
8083 SetRect( &rect, -5, -5, 5, 5 );
8084 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8085 count = 0;
8086 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8087 {
8088 if (msg.message != WM_PAINT) DispatchMessage( &msg );
8089 else
8090 {
8091 flush_sequence();
8092 DispatchMessage( &msg );
8093 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8094 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8095 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8096 if (++count > 10) break;
8097 }
8098 }
8099 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8100
8101 trace("now without DispatchMessage\n");
8102 flush_sequence();
8103 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8104 count = 0;
8105 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8106 {
8107 if (msg.message != WM_PAINT) DispatchMessage( &msg );
8108 else
8109 {
8110 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8111 flush_sequence();
8112 /* this will send WM_NCCPAINT just like DispatchMessage does */
8113 GetUpdateRgn( hwnd, hrgn, TRUE );
8114 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8115 DeleteObject( hrgn );
8116 GetClientRect( hwnd, &rect );
8117 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
8118 ok( !count, "Got multiple WM_PAINTs\n" );
8119 if (++count > 10) break;
8120 }
8121 }
8122 DestroyWindow(hwnd);
8123 }
8124
8125
8126 static const struct message WmUser[] = {
8127 { WM_USER, sent },
8128 { 0 }
8129 };
8130
8131 struct sendmsg_info
8132 {
8133 HWND hwnd;
8134 DWORD timeout;
8135 DWORD ret;
8136 };
8137
8138 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8139 {
8140 struct sendmsg_info *info = arg;
8141 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8142 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
8143 return 0;
8144 }
8145
8146 static void wait_for_thread( HANDLE thread )
8147 {
8148 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8149 {
8150 MSG msg;
8151 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8152 }
8153 }
8154
8155 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8156 {
8157 if (message == WM_USER) Sleep(200);
8158 return MsgCheckProcA( hwnd, message, wParam, lParam );
8159 }
8160
8161 static void test_SendMessageTimeout(void)
8162 {
8163 HANDLE thread;
8164 struct sendmsg_info info;
8165 DWORD tid;
8166
8167 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8168 100, 100, 200, 200, 0, 0, 0, NULL);
8169 flush_events();
8170 flush_sequence();
8171
8172 info.timeout = 1000;
8173 info.ret = 0xdeadbeef;
8174 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8175 wait_for_thread( thread );
8176 CloseHandle( thread );
8177 ok( info.ret == 1, "SendMessageTimeout failed\n" );
8178 ok_sequence( WmUser, "WmUser", FALSE );
8179
8180 info.timeout = 1;
8181 info.ret = 0xdeadbeef;
8182 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8183 Sleep(100); /* SendMessageTimeout should time out here */
8184 wait_for_thread( thread );
8185 CloseHandle( thread );
8186 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8187 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8188
8189 /* 0 means infinite timeout */
8190 info.timeout = 0;
8191 info.ret = 0xdeadbeef;
8192 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8193 Sleep(100);
8194 wait_for_thread( thread );
8195 CloseHandle( thread );
8196 ok( info.ret == 1, "SendMessageTimeout failed\n" );
8197 ok_sequence( WmUser, "WmUser", FALSE );
8198
8199 /* timeout is treated as signed despite the prototype */
8200 info.timeout = 0x7fffffff;
8201 info.ret = 0xdeadbeef;
8202 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8203 Sleep(100);
8204 wait_for_thread( thread );
8205 CloseHandle( thread );
8206 ok( info.ret == 1, "SendMessageTimeout failed\n" );
8207 ok_sequence( WmUser, "WmUser", FALSE );
8208
8209 info.timeout = 0x80000000;
8210 info.ret = 0xdeadbeef;
8211 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8212 Sleep(100);
8213 wait_for_thread( thread );
8214 CloseHandle( thread );
8215 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8216 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8217
8218 /* now check for timeout during message processing */
8219 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8220 info.timeout = 100;
8221 info.ret = 0xdeadbeef;
8222 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8223 wait_for_thread( thread );
8224 CloseHandle( thread );
8225 /* we should time out but still get the message */
8226 ok( info.ret == 0, "SendMessageTimeout failed\n" );
8227 ok_sequence( WmUser, "WmUser", FALSE );
8228
8229 DestroyWindow( info.hwnd );
8230 }
8231
8232
8233 /****************** edit message test *************************/
8234 #define ID_EDIT 0x1234
8235 static const struct message sl_edit_setfocus[] =
8236 {
8237 { HCBT_SETFOCUS, hook },
8238 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8239 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8240 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8241 { WM_SETFOCUS, sent|wparam, 0 },
8242 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8243 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8244 { WM_CTLCOLOREDIT, sent|parent },
8245 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8246 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8247 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8248 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8249 { 0 }
8250 };
8251 static const struct message ml_edit_setfocus[] =
8252 {
8253 { HCBT_SETFOCUS, hook },
8254 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8255 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8256 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8257 { WM_SETFOCUS, sent|wparam, 0 },
8258 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8259 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8260 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8261 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8262 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8263 { 0 }
8264 };
8265 static const struct message sl_edit_killfocus[] =
8266 {
8267 { HCBT_SETFOCUS, hook },
8268 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8269 { WM_KILLFOCUS, sent|wparam, 0 },
8270 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8271 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8272 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8273 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8274 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8275 { 0 }
8276 };
8277 static const struct message sl_edit_lbutton_dblclk[] =
8278 {
8279 { WM_LBUTTONDBLCLK, sent },
8280 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8281 { 0 }
8282 };
8283 static const struct message sl_edit_lbutton_down[] =
8284 {
8285 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8286 { HCBT_SETFOCUS, hook },
8287 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8288 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8289 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8290 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8291 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8292 { WM_CTLCOLOREDIT, sent|parent },
8293 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8294 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8295 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8296 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8297 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8298 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8299 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8300 { WM_CTLCOLOREDIT, sent|parent|optional },
8301 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8302 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8303 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8304 { 0 }
8305 };
8306 static const struct message ml_edit_lbutton_down[] =
8307 {
8308 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8309 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8310 { HCBT_SETFOCUS, hook },
8311 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8312 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8313 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8314 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8315 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8316 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8317 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8318 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8319 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8320 { 0 }
8321 };
8322 static const struct message sl_edit_lbutton_up[] =
8323 {
8324 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8325 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8326 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8327 { WM_CAPTURECHANGED, sent|defwinproc },
8328 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8329 { 0 }
8330 };
8331 static const struct message ml_edit_lbutton_up[] =
8332 {
8333 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8334 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8335 { WM_CAPTURECHANGED, sent|defwinproc },
8336 { 0 }
8337 };
8338
8339 static WNDPROC old_edit_proc;
8340
8341 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8342 {
8343 static long defwndproc_counter = 0;
8344 LRESULT ret;
8345 struct message msg;
8346
8347 trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
8348
8349 /* explicitly ignore WM_GETICON message */
8350 if (message == WM_GETICON) return 0;
8351
8352 msg.message = message;
8353 msg.flags = sent|wparam|lparam;
8354 if (defwndproc_counter) msg.flags |= defwinproc;
8355 msg.wParam = wParam;
8356 msg.lParam = lParam;
8357 add_message(&msg);
8358
8359 defwndproc_counter++;
8360 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8361 defwndproc_counter--;
8362
8363 return ret;
8364 }
8365
8366 static void subclass_edit(void)
8367 {
8368 WNDCLASSA cls;
8369
8370 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8371
8372 old_edit_proc = cls.lpfnWndProc;
8373
8374 cls.hInstance = GetModuleHandle(0);
8375 cls.lpfnWndProc = edit_hook_proc;
8376 cls.lpszClassName = "my_edit_class";
8377 UnregisterClass(cls.lpszClassName, cls.hInstance);
8378 if (!RegisterClassA(&cls)) assert(0);
8379 }
8380
8381 static void test_edit_messages(void)
8382 {
8383 HWND hwnd, parent;
8384 DWORD dlg_code;
8385
8386 subclass_edit();
8387 log_all_parent_messages++;
8388
8389 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8390 100, 100, 200, 200, 0, 0, 0, NULL);
8391 ok (parent != 0, "Failed to create parent window\n");
8392
8393 /* test single line edit */
8394 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8395 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8396 ok(hwnd != 0, "Failed to create edit window\n");
8397
8398 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8399 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8400
8401 ShowWindow(hwnd, SW_SHOW);
8402 UpdateWindow(hwnd);
8403 SetFocus(0);
8404 flush_sequence();
8405
8406 SetFocus(hwnd);
8407 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8408
8409 SetFocus(0);
8410 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8411
8412 SetFocus(0);
8413 ReleaseCapture();
8414 flush_sequence();
8415
8416 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8417 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8418
8419 SetFocus(0);
8420 ReleaseCapture();
8421 flush_sequence();
8422
8423 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8424 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8425
8426 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8427 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8428
8429 DestroyWindow(hwnd);
8430
8431 /* test multiline edit */
8432 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8433 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8434 ok(hwnd != 0, "Failed to create edit window\n");
8435
8436 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8437 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8438 "wrong dlg_code %08x\n", dlg_code);
8439
8440 ShowWindow(hwnd, SW_SHOW);
8441 UpdateWindow(hwnd);
8442 SetFocus(0);
8443 flush_sequence();
8444
8445 SetFocus(hwnd);
8446 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8447
8448 SetFocus(0);
8449 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8450
8451 SetFocus(0);
8452 ReleaseCapture();
8453 flush_sequence();
8454
8455 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8456 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8457
8458 SetFocus(0);
8459 ReleaseCapture();
8460 flush_sequence();
8461
8462 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8463 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8464
8465 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8466 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8467
8468 DestroyWindow(hwnd);
8469 DestroyWindow(parent);
8470
8471 log_all_parent_messages--;
8472 }
8473
8474 /**************************** End of Edit test ******************************/
8475
8476 static const struct message WmKeyDownSkippedSeq[] =
8477 {
8478 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8479 { 0 }
8480 };
8481 static const struct message WmKeyUpSkippedSeq[] =
8482 {
8483 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8484 { 0 }
8485 };
8486
8487 #define EV_START_STOP 0
8488 #define EV_SENDMSG 1
8489 #define EV_ACK 2
8490
8491 struct peekmsg_info
8492 {
8493 HWND hwnd;
8494 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8495 };
8496
8497 static DWORD CALLBACK send_msg_thread_2(void *param)
8498 {
8499 DWORD ret;
8500 struct peekmsg_info *info = param;
8501
8502 trace("thread: waiting for start\n");
8503 WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
8504 trace("thread: looping\n");
8505
8506 while (1)
8507 {
8508 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8509
8510 switch (ret)
8511 {
8512 case WAIT_OBJECT_0 + EV_START_STOP:
8513 trace("thread: exiting\n");
8514 return 0;
8515
8516 case WAIT_OBJECT_0 + EV_SENDMSG:
8517 trace("thread: sending message\n");
8518 SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
8519 SetEvent(info->hevent[EV_ACK]);
8520 break;
8521
8522 default:
8523 trace("unexpected return: %04x\n", ret);
8524 assert(0);
8525 break;
8526 }
8527 }
8528 return 0;
8529 }
8530
8531 static void test_PeekMessage(void)
8532 {
8533 MSG msg;
8534 HANDLE hthread;
8535 DWORD tid, qstatus;
8536 UINT qs_all_input = QS_ALLINPUT;
8537 UINT qs_input = QS_INPUT;
8538 BOOL ret;
8539 struct peekmsg_info info;
8540
8541 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8542 100, 100, 200, 200, 0, 0, 0, NULL);
8543 assert(info.hwnd);
8544 ShowWindow(info.hwnd, SW_SHOW);
8545 UpdateWindow(info.hwnd);
8546 SetFocus(info.hwnd);
8547
8548 info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
8549 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8550 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8551
8552 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8553 Sleep(100);
8554
8555 trace("signalling to start looping\n");
8556 SetEvent(info.hevent[EV_START_STOP]);
8557
8558 flush_events();
8559 flush_sequence();
8560
8561 SetLastError(0xdeadbeef);
8562 qstatus = GetQueueStatus(qs_all_input);
8563 if (GetLastError() == ERROR_INVALID_FLAGS)
8564 {
8565 trace("QS_RAWINPUT not supported on this platform\n");
8566 qs_all_input &= ~QS_RAWINPUT;
8567 qs_input &= ~QS_RAWINPUT;
8568 }
8569 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8570
8571 trace("signalling to send message\n");
8572 SetEvent(info.hevent[EV_SENDMSG]);
8573 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8574
8575 /* pass invalid QS_xxxx flags */
8576 SetLastError(0xdeadbeef);
8577 qstatus = GetQueueStatus(0xffffffff);
8578 ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
8579 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8580
8581 qstatus = GetQueueStatus(qs_all_input);
8582 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8583 "wrong qstatus %08x\n", qstatus);
8584
8585 msg.message = 0;
8586 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8587 ok(!ret,
8588 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8589 msg.message);
8590 ok_sequence(WmUser, "WmUser", FALSE);
8591
8592 qstatus = GetQueueStatus(qs_all_input);
8593 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8594
8595 keybd_event('N', 0, 0, 0);
8596 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8597 qstatus = GetQueueStatus(qs_all_input);
8598 ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8599 "wrong qstatus %08x\n", qstatus);
8600
8601 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8602 qstatus = GetQueueStatus(qs_all_input);
8603 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8604 "wrong qstatus %08x\n", qstatus);
8605
8606 InvalidateRect(info.hwnd, NULL, FALSE);
8607 qstatus = GetQueueStatus(qs_all_input);
8608 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8609 "wrong qstatus %08x\n", qstatus);
8610
8611 trace("signalling to send message\n");
8612 SetEvent(info.hevent[EV_SENDMSG]);
8613 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8614
8615 qstatus = GetQueueStatus(qs_all_input);
8616 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8617 "wrong qstatus %08x\n", qstatus);
8618
8619 msg.message = 0;
8620 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8621 ok(!ret,
8622 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8623 msg.message);
8624 ok_sequence(WmUser, "WmUser", FALSE);
8625
8626 qstatus = GetQueueStatus(qs_all_input);
8627 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8628 "wrong qstatus %08x\n", qstatus);
8629
8630 trace("signalling to send message\n");
8631 SetEvent(info.hevent[EV_SENDMSG]);
8632 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8633
8634 qstatus = GetQueueStatus(qs_all_input);
8635 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8636 "wrong qstatus %08x\n", qstatus);
8637
8638 msg.message = 0;
8639 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8640 ok(!ret,
8641 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8642 msg.message);
8643 ok_sequence(WmUser, "WmUser", FALSE);
8644
8645 qstatus = GetQueueStatus(qs_all_input);
8646 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8647 "wrong qstatus %08x\n", qstatus);
8648
8649 msg.message = 0;
8650 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8651 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8652 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8653 ret, msg.message, msg.wParam);
8654 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8655
8656 qstatus = GetQueueStatus(qs_all_input);
8657 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8658 "wrong qstatus %08x\n", qstatus);
8659
8660 msg.message = 0;
8661 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8662 ok(!ret,
8663 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8664 msg.message);
8665 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8666
8667 qstatus = GetQueueStatus(qs_all_input);
8668 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8669 "wrong qstatus %08x\n", qstatus);
8670
8671 msg.message = 0;
8672 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8673 ok(ret && msg.message == WM_PAINT,
8674 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8675 DispatchMessageA(&msg);
8676 ok_sequence(WmPaint, "WmPaint", FALSE);
8677
8678 qstatus = GetQueueStatus(qs_all_input);
8679 ok(qstatus == MAKELONG(0, QS_KEY),
8680 "wrong qstatus %08x\n", qstatus);
8681
8682 msg.message = 0;
8683 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8684 ok(!ret,
8685 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8686 msg.message);
8687 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8688
8689 qstatus = GetQueueStatus(qs_all_input);
8690 ok(qstatus == MAKELONG(0, QS_KEY),
8691 "wrong qstatus %08x\n", qstatus);
8692
8693 trace("signalling to send message\n");
8694 SetEvent(info.hevent[EV_SENDMSG]);
8695 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8696
8697 qstatus = GetQueueStatus(qs_all_input);
8698 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8699 "wrong qstatus %08x\n", qstatus);
8700
8701 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8702
8703 qstatus = GetQueueStatus(qs_all_input);
8704 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8705 "wrong qstatus %08x\n", qstatus);
8706
8707 msg.message = 0;
8708 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8709 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8710 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8711 ret, msg.message, msg.wParam);
8712 ok_sequence(WmUser, "WmUser", FALSE);
8713
8714 qstatus = GetQueueStatus(qs_all_input);
8715 ok(qstatus == MAKELONG(0, QS_KEY),
8716 "wrong qstatus %08x\n", qstatus);
8717
8718 msg.message = 0;
8719 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8720 ok(!ret,
8721 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8722 msg.message);
8723 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8724
8725 qstatus = GetQueueStatus(qs_all_input);
8726 ok(qstatus == MAKELONG(0, QS_KEY),
8727 "wrong qstatus %08x\n", qstatus);
8728
8729 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8730
8731 qstatus = GetQueueStatus(qs_all_input);
8732 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8733 "wrong qstatus %08x\n", qstatus);
8734
8735 trace("signalling to send message\n");
8736 SetEvent(info.hevent[EV_SENDMSG]);
8737 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8738
8739 qstatus = GetQueueStatus(qs_all_input);
8740 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8741 "wrong qstatus %08x\n", qstatus);
8742
8743 msg.message = 0;
8744 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
8745 ok(!ret,
8746 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8747 msg.message);
8748 ok_sequence(WmUser, "WmUser", FALSE);
8749
8750 qstatus = GetQueueStatus(qs_all_input);
8751 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8752 "wrong qstatus %08x\n", qstatus);
8753
8754 msg.message = 0;
8755 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8756 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8757 else /* workaround for a missing QS_RAWINPUT support */
8758 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
8759 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
8760 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
8761 ret, msg.message, msg.wParam);
8762 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
8763
8764 qstatus = GetQueueStatus(qs_all_input);
8765 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8766 "wrong qstatus %08x\n", qstatus);
8767
8768 msg.message = 0;
8769 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8770 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8771 else /* workaround for a missing QS_RAWINPUT support */
8772 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
8773 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
8774 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
8775 ret, msg.message, msg.wParam);
8776 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
8777
8778 qstatus = GetQueueStatus(qs_all_input);
8779 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8780 "wrong qstatus %08x\n", qstatus);
8781
8782 msg.message = 0;
8783 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
8784 ok(!ret,
8785 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8786 msg.message);
8787 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8788
8789 qstatus = GetQueueStatus(qs_all_input);
8790 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8791 "wrong qstatus %08x\n", qstatus);
8792
8793 msg.message = 0;
8794 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8795 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8796 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8797 ret, msg.message, msg.wParam);
8798 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8799
8800 qstatus = GetQueueStatus(qs_all_input);
8801 ok(qstatus == 0,
8802 "wrong qstatus %08x\n", qstatus);
8803
8804 msg.message = 0;
8805 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8806 ok(!ret,
8807 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8808 msg.message);
8809 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8810
8811 qstatus = GetQueueStatus(qs_all_input);
8812 ok(qstatus == 0,
8813 "wrong qstatus %08x\n", qstatus);
8814
8815 /* test whether presence of the quit flag in the queue affects
8816 * the queue state
8817 */
8818 PostQuitMessage(0x1234abcd);
8819
8820 qstatus = GetQueueStatus(qs_all_input);
8821 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8822 "wrong qstatus %08x\n", qstatus);
8823
8824 PostMessageA(info.hwnd, WM_USER, 0, 0);
8825
8826 qstatus = GetQueueStatus(qs_all_input);
8827 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8828 "wrong qstatus %08x\n", qstatus);
8829
8830 msg.message = 0;
8831 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8832 ok(ret && msg.message == WM_USER,
8833 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
8834 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8835
8836 qstatus = GetQueueStatus(qs_all_input);
8837 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8838 "wrong qstatus %08x\n", qstatus);
8839
8840 msg.message = 0;
8841 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8842 ok(ret && msg.message == WM_QUIT,
8843 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
8844 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
8845 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
8846 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8847
8848 qstatus = GetQueueStatus(qs_all_input);
8849 todo_wine {
8850 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8851 "wrong qstatus %08x\n", qstatus);
8852 }
8853
8854 msg.message = 0;
8855 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8856 ok(!ret,
8857 "PeekMessageA should have returned FALSE instead of msg %04x\n",
8858 msg.message);
8859 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8860
8861 qstatus = GetQueueStatus(qs_all_input);
8862 ok(qstatus == 0,
8863 "wrong qstatus %08x\n", qstatus);
8864
8865 trace("signalling to exit\n");
8866 SetEvent(info.hevent[EV_START_STOP]);
8867
8868 WaitForSingleObject(hthread, INFINITE);
8869
8870 CloseHandle(hthread);
8871 CloseHandle(info.hevent[0]);
8872 CloseHandle(info.hevent[1]);
8873 CloseHandle(info.hevent[2]);
8874
8875 DestroyWindow(info.hwnd);
8876 }
8877
8878 static void wait_move_event(HWND hwnd, int x, int y)
8879 {
8880 MSG msg;
8881 DWORD time;
8882 BOOL ret;
8883 int go = 0;
8884
8885 time = GetTickCount();
8886 while (GetTickCount() - time < 200 && !go) {
8887 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8888 go = ret && msg.pt.x > x && msg.pt.y > y;
8889 }
8890 }
8891
8892 #define STEP 20
8893 static void test_PeekMessage2(void)
8894 {
8895 HWND hwnd;
8896 BOOL ret;
8897 MSG msg;
8898 UINT message;
8899 DWORD time1, time2, time3;
8900 int x1, y1, x2, y2, x3, y3;
8901 POINT pos;
8902
8903 time1 = time2 = time3 = 0;
8904 x1 = y1 = x2 = y2 = x3 = y3 = 0;
8905
8906 /* Initialise window and make sure it is ready for events */
8907 hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
8908 10, 10, 800, 800, NULL, NULL, NULL, NULL);
8909 assert(hwnd);
8910 trace("Window for test_PeekMessage2 %p\n", hwnd);
8911 ShowWindow(hwnd, SW_SHOW);
8912 UpdateWindow(hwnd);
8913 SetFocus(hwnd);
8914 GetCursorPos(&pos);
8915 SetCursorPos(100, 100);
8916 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
8917 flush_events();
8918
8919 /* Do initial mousemove, wait until we can see it
8920 and then do our test peek with PM_NOREMOVE. */
8921 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8922 wait_move_event(hwnd, 80, 80);
8923
8924 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8925 ok(ret, "no message available\n");
8926 if (ret) {
8927 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8928 message = msg.message;
8929 time1 = msg.time;
8930 x1 = msg.pt.x;
8931 y1 = msg.pt.y;
8932 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8933 }
8934
8935 /* Allow time to advance a bit, and then simulate the user moving their
8936 * mouse around. After that we peek again with PM_NOREMOVE.
8937 * Although the previous mousemove message was never removed, the
8938 * mousemove we now peek should reflect the recent mouse movements
8939 * because the input queue will merge the move events. */
8940 Sleep(2);
8941 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8942 wait_move_event(hwnd, x1, y1);
8943
8944 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8945 ok(ret, "no message available\n");
8946 if (ret) {
8947 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8948 message = msg.message;
8949 time2 = msg.time;
8950 x2 = msg.pt.x;
8951 y2 = msg.pt.y;
8952 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8953 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
8954 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
8955 }
8956
8957 /* Have another go, to drive the point home */
8958 Sleep(2);
8959 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8960 wait_move_event(hwnd, x2, y2);
8961
8962 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8963 ok(ret, "no message available\n");
8964 if (ret) {
8965 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8966 message = msg.message;
8967 time3 = msg.time;
8968 x3 = msg.pt.x;
8969 y3 = msg.pt.y;
8970 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8971 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
8972 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
8973 }
8974
8975 DestroyWindow(hwnd);
8976 SetCursorPos(pos.x, pos.y);
8977 flush_events();
8978 }
8979
8980 static void test_quit_message(void)
8981 {
8982 MSG msg;
8983 BOOL ret;
8984
8985 /* test using PostQuitMessage */
8986 PostQuitMessage(0xbeef);
8987
8988 ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8989 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8990 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8991 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
8992
8993 ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8994 ok(ret, "PostMessage failed with error %d\n", GetLastError());
8995
8996 ret = GetMessage(&msg, NULL, 0, 0);
8997 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8998 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8999
9000 /* note: WM_QUIT message received after WM_USER message */
9001 ret = GetMessage(&msg, NULL, 0, 0);
9002 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9003 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9004 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9005
9006 ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9007 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9008
9009 /* now test with PostThreadMessage - different behaviour! */
9010 PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9011
9012 ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9013 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9014 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9015 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9016
9017 ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9018 ok(ret, "PostMessage failed with error %d\n", GetLastError());
9019
9020 /* note: we receive the WM_QUIT message first this time */
9021 ret = GetMessage(&msg, NULL, 0, 0);
9022 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9023 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9024 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9025
9026 ret = GetMessage(&msg, NULL, 0, 0);
9027 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9028 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9029 }
9030
9031 static const struct message WmMouseHoverSeq[] = {
9032 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9033 { WM_MOUSEACTIVATE, sent|optional },
9034 { WM_TIMER, sent|optional }, /* XP sends it */
9035 { WM_SYSTIMER, sent },
9036 { WM_MOUSEHOVER, sent|wparam, 0 },
9037 { 0 }
9038 };
9039
9040 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9041 {
9042 MSG msg;
9043 DWORD start_ticks, end_ticks;
9044
9045 start_ticks = GetTickCount();
9046 /* add some deviation (5%) to cover not expected delays */
9047 start_ticks += timeout / 20;
9048
9049 do
9050 {
9051 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9052 {
9053 /* Timer proc messages are not dispatched to the window proc,
9054 * and therefore not logged.
9055 */
9056 if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9057 {
9058 struct message s_msg;
9059
9060 s_msg.message = msg.message;
9061 s_msg.flags = sent|wparam|lparam;
9062 s_msg.wParam = msg.wParam;
9063 s_msg.lParam = msg.lParam;
9064 add_message(&s_msg);
9065 }
9066 DispatchMessage(&msg);
9067 }
9068
9069 end_ticks = GetTickCount();
9070
9071 /* inject WM_MOUSEMOVE to see how it changes tracking */
9072 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9073 {
9074 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9075 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9076
9077 inject_mouse_move = FALSE;
9078 }
9079 } while (start_ticks + timeout >= end_ticks);
9080 }
9081
9082 static void test_TrackMouseEvent(void)
9083 {
9084 TRACKMOUSEEVENT tme;
9085 BOOL ret;
9086 HWND hwnd, hchild;
9087 RECT rc_parent, rc_child;
9088 UINT default_hover_time, hover_width = 0, hover_height = 0;
9089
9090 #define track_hover(track_hwnd, track_hover_time) \
9091 tme.cbSize = sizeof(tme); \
9092 tme.dwFlags = TME_HOVER; \
9093 tme.hwndTrack = track_hwnd; \
9094 tme.dwHoverTime = track_hover_time; \
9095 SetLastError(0xdeadbeef); \
9096 ret = pTrackMouseEvent(&tme); \
9097 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9098
9099 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9100 tme.cbSize = sizeof(tme); \
9101 tme.dwFlags = TME_QUERY; \
9102 tme.hwndTrack = (HWND)0xdeadbeef; \
9103 tme.dwHoverTime = 0xdeadbeef; \
9104 SetLastError(0xdeadbeef); \
9105 ret = pTrackMouseEvent(&tme); \
9106 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9107 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9108 ok(tme.dwFlags == (expected_track_flags), \
9109 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9110 ok(tme.hwndTrack == (expected_track_hwnd), \
9111 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9112 ok(tme.dwHoverTime == (expected_hover_time), \
9113 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9114
9115 #define track_hover_cancel(track_hwnd) \
9116 tme.cbSize = sizeof(tme); \
9117 tme.dwFlags = TME_HOVER | TME_CANCEL; \
9118 tme.hwndTrack = track_hwnd; \
9119 tme.dwHoverTime = 0xdeadbeef; \
9120 SetLastError(0xdeadbeef); \
9121 ret = pTrackMouseEvent(&tme); \
9122 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9123
9124 default_hover_time = 0xdeadbeef;
9125 SetLastError(0xdeadbeef);
9126 ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9127 ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9128 if (!ret) default_hover_time = 400;
9129 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9130
9131 SetLastError(0xdeadbeef);
9132 ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9133 ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9134 if (!ret) hover_width = 4;
9135 SetLastError(0xdeadbeef);
9136 ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9137 ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9138 if (!ret) hover_height = 4;
9139 trace("hover rect is %u x %d\n", hover_width, hover_height);
9140
9141 hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9142 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9143 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9144 NULL, NULL, 0);
9145 assert(hwnd);
9146
9147 hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9148 WS_CHILD | WS_BORDER | WS_VISIBLE,
9149 50, 50, 200, 200, hwnd,
9150 NULL, NULL, 0);
9151 assert(hchild);
9152
9153 flush_events();
9154 flush_sequence();
9155
9156 tme.cbSize = 0;
9157 tme.dwFlags = TME_QUERY;
9158 tme.hwndTrack = (HWND)0xdeadbeef;
9159 tme.dwHoverTime = 0xdeadbeef;
9160 SetLastError(0xdeadbeef);
9161 ret = pTrackMouseEvent(&tme);
9162 ok(!ret, "TrackMouseEvent should fail\n");
9163 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
9164
9165 tme.cbSize = sizeof(tme);
9166 tme.dwFlags = TME_HOVER;
9167 tme.hwndTrack = (HWND)0xdeadbeef;
9168 tme.dwHoverTime = 0xdeadbeef;
9169 SetLastError(0xdeadbeef);
9170 ret = pTrackMouseEvent(&tme);
9171 ok(!ret, "TrackMouseEvent should fail\n");
9172 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
9173
9174 tme.cbSize = sizeof(tme);
9175 tme.dwFlags = TME_HOVER | TME_CANCEL;
9176 tme.hwndTrack = (HWND)0xdeadbeef;
9177 tme.dwHoverTime = 0xdeadbeef;
9178 SetLastError(0xdeadbeef);
9179 ret = pTrackMouseEvent(&tme);
9180 ok(!ret, "TrackMouseEvent should fail\n");
9181 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
9182
9183 GetWindowRect(hwnd, &rc_parent);
9184 GetWindowRect(hchild, &rc_child);
9185 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9186
9187 /* Process messages so that the system updates its internal current
9188 * window and hittest, otherwise TrackMouseEvent calls don't have any
9189 * effect.
9190 */
9191 flush_events();
9192 flush_sequence();
9193
9194 track_query(0, NULL, 0);
9195 track_hover(hchild, 0);
9196 track_query(0, NULL, 0);
9197
9198 flush_events();
9199 flush_sequence();
9200
9201 track_hover(hwnd, 0);
9202 track_query(TME_HOVER, hwnd, default_hover_time);
9203
9204 pump_msg_loop_timeout(default_hover_time, FALSE);
9205 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9206
9207 track_query(0, NULL, 0);
9208
9209 track_hover(hwnd, HOVER_DEFAULT);
9210 track_query(TME_HOVER, hwnd, default_hover_time);
9211
9212 Sleep(default_hover_time / 2);
9213 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9214 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9215
9216 track_query(TME_HOVER, hwnd, default_hover_time);
9217
9218 pump_msg_loop_timeout(default_hover_time / 2, FALSE);
9219 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9220
9221 track_query(0, NULL, 0);
9222
9223 track_hover(hwnd, HOVER_DEFAULT);
9224 track_query(TME_HOVER, hwnd, default_hover_time);
9225
9226 pump_msg_loop_timeout(default_hover_time, TRUE);
9227 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9228
9229 track_query(0, NULL, 0);
9230
9231 track_hover(hwnd, HOVER_DEFAULT);
9232 track_query(TME_HOVER, hwnd, default_hover_time);
9233 track_hover_cancel(hwnd);
9234
9235 DestroyWindow(hwnd);
9236
9237 #undef track_hover
9238 #undef track_query
9239 #undef track_hover_cancel
9240 }
9241
9242
9243 static const struct message WmSetWindowRgn[] = {
9244 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9245 { WM_NCCALCSIZE, sent|wparam, 1 },
9246 { WM_NCPAINT, sent }, /* wparam != 1 */
9247 { WM_GETTEXT, sent|defwinproc|optional },
9248 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9249 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9250 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9251 { 0 }
9252 };
9253
9254 static const struct message WmSetWindowRgn_no_redraw[] = {
9255 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9256 { WM_NCCALCSIZE, sent|wparam, 1 },
9257 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9258 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9259 { 0 }
9260 };
9261
9262 static const struct message WmSetWindowRgn_clear[] = {
9263 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9264 { WM_NCCALCSIZE, sent|wparam, 1 },
9265 { WM_NCPAINT, sent }, /* wparam != 1 */
9266 { WM_GETTEXT, sent|defwinproc|optional },
9267 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9268 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9269 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9270 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9271 { WM_GETTEXT, sent|defwinproc|optional },
9272 { WM_ERASEBKGND, sent|optional },
9273 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9274 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9275 { 0 }
9276 };
9277
9278 static void test_SetWindowRgn(void)
9279 {
9280 HRGN hrgn;
9281 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9282 100, 100, 200, 200, 0, 0, 0, NULL);
9283 ok( hwnd != 0, "Failed to create overlapped window\n" );
9284
9285 ShowWindow( hwnd, SW_SHOW );
9286 UpdateWindow( hwnd );
9287 flush_events();
9288 flush_sequence();
9289
9290 trace("testing SetWindowRgn\n");
9291 hrgn = CreateRectRgn( 0, 0, 150, 150 );
9292 SetWindowRgn( hwnd, hrgn, TRUE );
9293 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9294
9295 hrgn = CreateRectRgn( 30, 30, 160, 160 );
9296 SetWindowRgn( hwnd, hrgn, FALSE );
9297 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9298
9299 hrgn = CreateRectRgn( 0, 0, 180, 180 );
9300 SetWindowRgn( hwnd, hrgn, TRUE );
9301 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9302
9303 SetWindowRgn( hwnd, 0, TRUE );
9304 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9305
9306 DestroyWindow( hwnd );
9307 }
9308
9309 /*************************** ShowWindow() test ******************************/
9310 static const struct message WmShowNormal[] = {
9311 { WM_SHOWWINDOW, sent|wparam, 1 },
9312 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9313 { HCBT_ACTIVATE, hook },
9314 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9315 { HCBT_SETFOCUS, hook },
9316 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9317 { 0 }
9318 };
9319 static const struct message WmShow[] = {
9320 { WM_SHOWWINDOW, sent|wparam, 1 },
9321 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9322 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9323 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9324 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9325 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9326 { 0 }
9327 };
9328 static const struct message WmShowNoActivate_1[] = {
9329 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9330 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9331 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9332 { WM_MOVE, sent|defwinproc },
9333 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9334 { 0 }
9335 };
9336 static const struct message WmShowNoActivate_2[] = {
9337 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9338 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9339 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9340 { WM_MOVE, sent|defwinproc },
9341 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9342 { HCBT_SETFOCUS, hook|optional },
9343 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9344 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9345 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9346 { 0 }
9347 };
9348 static const struct message WmShowNA_1[] = {
9349 { WM_SHOWWINDOW, sent|wparam, 1 },
9350 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9351 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9352 { 0 }
9353 };
9354 static const struct message WmShowNA_2[] = {
9355 { WM_SHOWWINDOW, sent|wparam, 1 },
9356 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9357 { 0 }
9358 };
9359 static const struct message WmRestore_1[] = {
9360 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9361 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9362 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9363 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9364 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9365 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9366 { WM_MOVE, sent|defwinproc },
9367 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9368 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9369 { 0 }
9370 };
9371 static const struct message WmRestore_2[] = {
9372 { WM_SHOWWINDOW, sent|wparam, 1 },
9373 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9374 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9375 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9376 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9377 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9378 { 0 }
9379 };
9380 static const struct message WmRestore_3[] = {
9381 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9382 { WM_GETMINMAXINFO, sent },
9383 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9384 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9385 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9386 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9387 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9388 { WM_MOVE, sent|defwinproc },
9389 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9390 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9391 { 0 }
9392 };
9393 static const struct message WmRestore_4[] = {
9394 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9395 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9396 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9397 { WM_MOVE, sent|defwinproc },
9398 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9399 { 0 }
9400 };
9401 static const struct message WmRestore_5[] = {
9402 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
9403 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9404 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9405 { WM_MOVE, sent|defwinproc },
9406 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9407 { 0 }
9408 };
9409 static const struct message WmHide_1[] = {
9410 { WM_SHOWWINDOW, sent|wparam, 0 },
9411 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9412 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9413 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9414 { 0 }
9415 };
9416 static const struct message WmHide_2[] = {
9417 { WM_SHOWWINDOW, sent|wparam, 0 },
9418 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9419 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9420 { 0 }
9421 };
9422 static const struct message WmHide_3[] = {
9423 { WM_SHOWWINDOW, sent|wparam, 0 },
9424 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9425 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9426 { HCBT_SETFOCUS, hook },
9427 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9428 { 0 }
9429 };
9430 static const struct message WmShowMinimized_1[] = {
9431 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9432 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9433 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9434 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9435 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9436 { WM_MOVE, sent|defwinproc },
9437 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9438 { 0 }
9439 };
9440 static const struct message WmMinimize_1[] = {
9441 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9442 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9443 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9444 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9445 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9446 { WM_MOVE, sent|defwinproc },
9447 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9448 { 0 }
9449 };
9450 static const struct message WmMinimize_2[] = {
9451 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9452 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9453 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9454 { WM_MOVE, sent|defwinproc },
9455 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9456 { 0 }
9457 };
9458 static const struct message WmMinimize_3[] = {
9459 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9460 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9461 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9462 { WM_MOVE, sent|defwinproc },
9463 { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9464 { 0 }
9465 };
9466 static const struct message WmShowMinNoActivate[] = {
9467 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9468 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9469 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9470 { 0 }
9471 };
9472 static const struct message WmMinMax_1[] = {
9473 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9474 { 0 }
9475 };
9476 static const struct message WmMinMax_2[] = {
9477 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9478 { 0 }
9479 };
9480 static const struct message WmMinMax_3[] = {
9481 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9482 { 0 }
9483 };
9484 static const struct message WmMinMax_4[] = {
9485 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9486 { 0 }
9487 };
9488 static const struct message WmShowMaximized_1[] = {
9489 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9490 { WM_GETMINMAXINFO, sent },
9491 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9492 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9493 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9494 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9495 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9496 { WM_MOVE, sent|defwinproc },
9497 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9498 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9499 { 0 }
9500 };
9501 static const struct message WmShowMaximized_2[] = {
9502 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9503 { WM_GETMINMAXINFO, sent },
9504 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
9505 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9506 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
9507 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
9508 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9509 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9510 { WM_MOVE, sent|defwinproc },
9511 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9512 { HCBT_SETFOCUS, hook },
9513 { 0 }
9514 };
9515 static const struct message WmShowMaximized_3[] = {
9516 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9517 { WM_GETMINMAXINFO, sent },
9518 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9519 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9520 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9521 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9522 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9523 { WM_MOVE, sent|defwinproc },
9524 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9525 { 0 }
9526 };
9527
9528 static void test_ShowWindow(void)
9529 {
9530 /* ShowWindow commands in random order */
9531 static const struct
9532 {
9533 INT cmd; /* ShowWindow command */
9534 LPARAM ret; /* ShowWindow return value */
9535 DWORD style; /* window style after the command */
9536 const struct message *msg; /* message sequence the command produces */
9537 BOOL todo_msg; /* message sequence doesn't match what Wine does */
9538 } sw[] =
9539 {
9540 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
9541 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9542 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9543 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9544 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
9545 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
9546 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
9547 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9548 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
9549 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9550 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
9551 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
9552 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
9553 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9554 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
9555 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9556 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
9557 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9558 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
9559 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9560 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9561 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
9562 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
9563 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9564 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9565 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
9566 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
9567 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9568 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9569 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
9570 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9571 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
9572 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9573 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
9574 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
9575 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9576 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
9577 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9578 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9579 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
9580 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9581 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
9582 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9583 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
9584 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9585 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
9586 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
9587 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
9588 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
9589 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
9590 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9591 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9592 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9593 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
9594 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9595 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
9596 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
9597 };
9598 HWND hwnd;
9599 DWORD style;
9600 LPARAM ret;
9601 INT i;
9602
9603 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
9604 hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
9605 120, 120, 90, 90,
9606 0, 0, 0, NULL);
9607 assert(hwnd);
9608
9609 style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9610 ok(style == 0, "expected style 0, got %08x\n", style);
9611
9612 flush_events();
9613 flush_sequence();
9614
9615 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
9616 {
9617 static const char * const sw_cmd_name[13] =
9618 {
9619 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
9620 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
9621 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
9622 "SW_NORMALNA" /* 0xCC */
9623 };
9624 char comment[64];
9625 INT idx; /* index into the above array of names */
9626
9627 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
9628
9629 style = GetWindowLong(hwnd, GWL_STYLE);
9630 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
9631 ret = ShowWindow(hwnd, sw[i].cmd);
9632 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
9633 style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9634 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
9635
9636 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
9637 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
9638
9639 flush_events();
9640 flush_sequence();
9641 }
9642
9643 DestroyWindow(hwnd);
9644 }
9645
9646 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9647 {
9648 struct message msg;
9649
9650 trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
9651
9652 switch (message)
9653 {
9654 case WM_WINDOWPOSCHANGING:
9655 case WM_WINDOWPOSCHANGED:
9656 {
9657 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
9658
9659 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
9660 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
9661 winpos->hwnd, winpos->hwndInsertAfter,
9662 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
9663 dump_winpos_flags(winpos->flags);
9664
9665 /* Log only documented flags, win2k uses 0x1000 and 0x2000
9666 * in the high word for internal purposes
9667 */
9668 wParam = winpos->flags & 0xffff;
9669 /* We are not interested in the flags that don't match under XP and Win9x */
9670 wParam &= ~(SWP_NOZORDER);
9671 break;
9672 }
9673
9674 /* explicitly ignore WM_GETICON message */
9675 case WM_GETICON:
9676 return 0;
9677 }
9678
9679 msg.message = message;
9680 msg.flags = sent|wparam|lparam;
9681 msg.wParam = wParam;
9682 msg.lParam = lParam;
9683 add_message(&msg);
9684
9685 /* calling DefDlgProc leads to a recursion under XP */
9686
9687 switch (message)
9688 {
9689 case WM_INITDIALOG:
9690 case WM_GETDLGCODE:
9691 return 0;
9692 }
9693 return 1;
9694 }
9695
9696 static const struct message WmDefDlgSetFocus_1[] = {
9697 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9698 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9699 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9700 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9701 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9702 { HCBT_SETFOCUS, hook },
9703 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9704 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9705 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9706 { WM_SETFOCUS, sent|wparam, 0 },
9707 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9708 { WM_CTLCOLOREDIT, sent },
9709 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9710 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9711 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9712 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9713 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
9714 { 0 }
9715 };
9716 static const struct message WmDefDlgSetFocus_2[] = {
9717 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9718 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9719 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9720 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9721 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9722 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9723 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
9724 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9725 { 0 }
9726 };
9727 /* Creation of a dialog */
9728 static const struct message WmCreateDialogParamSeq_1[] = {
9729 { HCBT_CREATEWND, hook },
9730 { WM_NCCREATE, sent },
9731 { WM_NCCALCSIZE, sent|wparam, 0 },
9732 { WM_CREATE, sent },
9733 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9734 { WM_SIZE, sent|wparam, SIZE_RESTORED },
9735 { WM_MOVE, sent },
9736 { WM_SETFONT, sent },
9737 { WM_INITDIALOG, sent },
9738 { WM_CHANGEUISTATE, sent|optional },
9739 { 0 }
9740 };
9741 /* Creation of a dialog */
9742 static const struct message WmCreateDialogParamSeq_2[] = {
9743 { HCBT_CREATEWND, hook },
9744 { WM_NCCREATE, sent },
9745 { WM_NCCALCSIZE, sent|wparam, 0 },
9746 { WM_CREATE, sent },
9747 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9748 { WM_SIZE, sent|wparam, SIZE_RESTORED },
9749 { WM_MOVE, sent },
9750 { WM_CHANGEUISTATE, sent|optional },
9751 { 0 }
9752 };
9753
9754 static void test_dialog_messages(void)
9755 {
9756 WNDCLASS cls;
9757 HWND hdlg, hedit1, hedit2, hfocus;
9758 LRESULT ret;
9759
9760 #define set_selection(hctl, start, end) \
9761 ret = SendMessage(hctl, EM_SETSEL, start, end); \
9762 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
9763
9764 #define check_selection(hctl, start, end) \
9765 ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
9766 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
9767
9768 subclass_edit();
9769
9770 hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
9771 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
9772 0, 0, 100, 100, 0, 0, 0, NULL);
9773 ok(hdlg != 0, "Failed to create custom dialog window\n");
9774
9775 hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
9776 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9777 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
9778 ok(hedit1 != 0, "Failed to create edit control\n");
9779 hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
9780 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9781 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
9782 ok(hedit2 != 0, "Failed to create edit control\n");
9783
9784 SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
9785 SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
9786
9787 hfocus = GetFocus();
9788 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
9789
9790 SetFocus(hedit2);
9791 hfocus = GetFocus();
9792 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
9793
9794 check_selection(hedit1, 0, 0);
9795 check_selection(hedit2, 0, 0);
9796
9797 set_selection(hedit2, 0, -1);
9798 check_selection(hedit2, 0, 3);
9799
9800 SetFocus(0);
9801 hfocus = GetFocus();
9802 ok(hfocus == 0, "wrong focus %p\n", hfocus);
9803
9804 flush_sequence();
9805 ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9806 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9807 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
9808
9809 hfocus = GetFocus();
9810 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9811
9812 check_selection(hedit1, 0, 5);
9813 check_selection(hedit2, 0, 3);
9814
9815 flush_sequence();
9816 ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9817 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9818 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
9819
9820 hfocus = GetFocus();
9821 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9822
9823 check_selection(hedit1, 0, 5);
9824 check_selection(hedit2, 0, 3);
9825
9826 EndDialog(hdlg, 0);
9827 DestroyWindow(hedit1);
9828 DestroyWindow(hedit2);
9829 DestroyWindow(hdlg);
9830 flush_sequence();
9831
9832 #undef set_selection
9833 #undef check_selection
9834
9835 ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
9836 cls.lpszClassName = "MyDialogClass";
9837 cls.hInstance = GetModuleHandle(0);
9838 /* need a cast since a dlgproc is used as a wndproc */
9839 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
9840 if (!RegisterClass(&cls)) assert(0);
9841
9842 hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
9843 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9844 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
9845 EndDialog(hdlg, 0);
9846 DestroyWindow(hdlg);
9847 flush_sequence();
9848
9849 hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
9850 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9851 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
9852 EndDialog(hdlg, 0);
9853 DestroyWindow(hdlg);
9854 flush_sequence();
9855
9856 UnregisterClass(cls.lpszClassName, cls.hInstance);
9857 }
9858
9859 static void test_nullCallback(void)
9860 {
9861 HWND hwnd;
9862
9863 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9864 100, 100, 200, 200, 0, 0, 0, NULL);
9865 ok (hwnd != 0, "Failed to create overlapped window\n");
9866
9867 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
9868 flush_events();
9869 DestroyWindow(hwnd);
9870 }
9871
9872 static const struct message SetForegroundWindowSeq[] =
9873 {
9874 { WM_NCACTIVATE, sent|wparam, 0 },
9875 { WM_GETTEXT, sent|defwinproc|optional },
9876 { WM_ACTIVATE, sent|wparam, 0 },
9877 { WM_ACTIVATEAPP, sent|wparam, 0 },
9878 { WM_KILLFOCUS, sent },
9879 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9880 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
9881 { 0 }
9882 };
9883
9884 static void test_SetForegroundWindow(void)
9885 {
9886 HWND hwnd;
9887
9888 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
9889 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9890 100, 100, 200, 200, 0, 0, 0, NULL);
9891 ok (hwnd != 0, "Failed to create overlapped window\n");
9892 flush_sequence();
9893
9894 trace("SetForegroundWindow( 0 )\n");
9895 SetForegroundWindow( 0 );
9896 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
9897 trace("SetForegroundWindow( GetDesktopWindow() )\n");
9898 SetForegroundWindow( GetDesktopWindow() );
9899 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
9900 "foreground top level window", FALSE);
9901 trace("done\n");
9902
9903 DestroyWindow(hwnd);
9904 }
9905
9906 static void test_dbcs_wm_char(void)
9907 {
9908 BYTE dbch[2];
9909 WCHAR wch, bad_wch;
9910 HWND hwnd, hwnd2;
9911 MSG msg;
9912 DWORD time;
9913 POINT pt;
9914 DWORD_PTR res;
9915 CPINFOEXA cpinfo;
9916 UINT i, j, k;
9917 struct message wmCharSeq[2];
9918
9919 if (!pGetCPInfoExA)
9920 {
9921 skip("GetCPInfoExA is not available\n");
9922 return;
9923 }
9924
9925 pGetCPInfoExA( CP_ACP, 0, &cpinfo );
9926 if (cpinfo.MaxCharSize != 2)
9927 {
9928 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
9929 return;
9930 }
9931
9932 dbch[0] = dbch[1] = 0;
9933 wch = 0;
9934 bad_wch = cpinfo.UnicodeDefaultChar;
9935 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
9936 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
9937 for (k = 128; k <= 255; k++)
9938 {
9939 char str[2];
9940 WCHAR wstr[2];
9941 str[0] = j;
9942 str[1] = k;
9943 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
9944 WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
9945 (BYTE)str[0] == j && (BYTE)str[1] == k &&
9946 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
9947 {
9948 dbch[0] = j;
9949 dbch[1] = k;
9950 wch = wstr[0];
9951 break;
9952 }
9953 }
9954
9955 if (!wch)
9956 {
9957 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
9958 return;
9959 }
9960 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
9961 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
9962
9963 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
9964 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9965 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
9966 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9967 ok (hwnd != 0, "Failed to create overlapped window\n");
9968 ok (hwnd2 != 0, "Failed to create overlapped window\n");
9969 flush_sequence();
9970
9971 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
9972 wmCharSeq[0].message = WM_CHAR;
9973 wmCharSeq[0].flags = sent|wparam;
9974 wmCharSeq[0].wParam = wch;
9975
9976 /* posted message */
9977 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9978 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9979 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9980 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9981 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9982 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9983 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9984
9985 /* posted thread message */
9986 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
9987 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9988 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9989 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9990 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9991 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9992 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9993
9994 /* sent message */
9995 flush_sequence();
9996 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9997 ok_sequence( WmEmptySeq, "no messages", FALSE );
9998 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9999 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10000 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10001
10002 /* sent message with timeout */
10003 flush_sequence();
10004 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10005 ok_sequence( WmEmptySeq, "no messages", FALSE );
10006 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10007 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10008 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10009
10010 /* sent message with timeout and callback */
10011 flush_sequence();
10012 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10013 ok_sequence( WmEmptySeq, "no messages", FALSE );
10014 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10015 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10016 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10017
10018 /* sent message with callback */
10019 flush_sequence();
10020 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10021 ok_sequence( WmEmptySeq, "no messages", FALSE );
10022 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10023 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10024 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10025
10026 /* direct window proc call */
10027 flush_sequence();
10028 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10029 ok_sequence( WmEmptySeq, "no messages", FALSE );
10030 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10031 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10032
10033 /* dispatch message */
10034 msg.hwnd = hwnd;
10035 msg.message = WM_CHAR;
10036 msg.wParam = dbch[0];
10037 msg.lParam = 0;
10038 DispatchMessageA( &msg );
10039 ok_sequence( WmEmptySeq, "no messages", FALSE );
10040 msg.wParam = dbch[1];
10041 DispatchMessageA( &msg );
10042 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10043
10044 /* window handle is irrelevant */
10045 flush_sequence();
10046 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10047 ok_sequence( WmEmptySeq, "no messages", FALSE );
10048 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10049 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10050 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10051
10052 /* interleaved post and send */
10053 flush_sequence();
10054 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10055 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10056 ok_sequence( WmEmptySeq, "no messages", FALSE );
10057 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10058 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10059 ok_sequence( WmEmptySeq, "no messages", FALSE );
10060 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10061 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10062 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10063 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10064 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10065 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10066 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10067
10068 /* interleaved sent message and winproc */
10069 flush_sequence();
10070 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10071 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10072 ok_sequence( WmEmptySeq, "no messages", FALSE );
10073 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10074 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10075 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10076 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10077
10078 /* interleaved winproc and dispatch */
10079 msg.hwnd = hwnd;
10080 msg.message = WM_CHAR;
10081 msg.wParam = dbch[0];
10082 msg.lParam = 0;
10083 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10084 DispatchMessageA( &msg );
10085 ok_sequence( WmEmptySeq, "no messages", FALSE );
10086 msg.wParam = dbch[1];
10087 DispatchMessageA( &msg );
10088 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10089 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10090 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10091
10092 /* interleaved sends */
10093 flush_sequence();
10094 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10095 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
10096 ok_sequence( WmEmptySeq, "no messages", FALSE );
10097 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10098 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10099 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10100 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10101
10102 /* dbcs WM_CHAR */
10103 flush_sequence();
10104 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
10105 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10106 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10107
10108 /* other char messages are not magic */
10109 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
10110 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10111 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
10112 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10113 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10114 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
10115 ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10116 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
10117 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10118 ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10119
10120 /* test retrieving messages */
10121
10122 PostMessageW( hwnd, WM_CHAR, wch, 0 );
10123 ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10124 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10125 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10126 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10127 ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10128 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10129 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10130 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10131 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10132
10133 /* message filters */
10134 PostMessageW( hwnd, WM_CHAR, wch, 0 );
10135 ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10136 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10137 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10138 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10139 /* message id is filtered, hwnd is not */
10140 ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
10141 ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
10142 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10143 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10144 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10145 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10146
10147 /* mixing GetMessage and PostMessage */
10148 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
10149 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
10150 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10151 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10152 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10153 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10154 time = msg.time;
10155 pt = msg.pt;
10156 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
10157 ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10158 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10159 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10160 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10161 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10162 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
10163 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 );
10164 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10165
10166 /* without PM_REMOVE */
10167 PostMessageW( hwnd, WM_CHAR, wch, 0 );
10168 ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10169 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10170 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10171 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10172 ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10173 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10174 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10175 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10176 ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10177 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10178 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10179 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10180 ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10181 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10182 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10183 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10184 ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10185
10186 DestroyWindow(hwnd);
10187 }
10188
10189 #define ID_LISTBOX 0x000f
10190
10191 static const struct message wm_lb_setcursel_0[] =
10192 {
10193 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
10194 { WM_CTLCOLORLISTBOX, sent|parent },
10195 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10196 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10197 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10198 { 0 }
10199 };
10200 static const struct message wm_lb_setcursel_1[] =
10201 {
10202 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
10203 { WM_CTLCOLORLISTBOX, sent|parent },
10204 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
10205 { WM_CTLCOLORLISTBOX, sent|parent },
10206 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
10207 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10208 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10209 { 0 }
10210 };
10211 static const struct message wm_lb_setcursel_2[] =
10212 {
10213 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
10214 { WM_CTLCOLORLISTBOX, sent|parent },
10215 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
10216 { WM_CTLCOLORLISTBOX, sent|parent },
10217 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
10218 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10219 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10220 { 0 }
10221 };
10222 static const struct message wm_lb_click_0[] =
10223 {
10224 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
10225 { HCBT_SETFOCUS, hook },
10226 { WM_KILLFOCUS, sent|parent },
10227 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
10228 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10229 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10230 { WM_SETFOCUS, sent|defwinproc },
10231
10232 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
10233 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
10234 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10235 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
10236 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10237
10238 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
10239 { WM_CTLCOLORLISTBOX, sent|parent },
10240 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
10241 { WM_CTLCOLORLISTBOX, sent|parent },
10242 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10243 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
10244
10245 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10246 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10247
10248 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10249 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10250 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
10251 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
10252 { 0 }
10253 };
10254
10255 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
10256
10257 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
10258
10259 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10260 {
10261 static long defwndproc_counter = 0;
10262 LRESULT ret;
10263 struct message msg;
10264
10265 /* do not log painting messages */
10266 if (message != WM_PAINT &&
10267 message != WM_NCPAINT &&
10268 message != WM_SYNCPAINT &&
10269 message != WM_ERASEBKGND &&
10270 message != WM_NCHITTEST &&
10271 message != WM_GETTEXT &&
10272 message != WM_GETICON &&
10273 message != WM_DEVICECHANGE)
10274 {
10275 trace("listbox: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
10276
10277 msg.message = message;
10278 msg.flags = sent|wparam|lparam;
10279 if (defwndproc_counter) msg.flags |= defwinproc;
10280 msg.wParam = wp;
10281 msg.lParam = lp;
10282 add_message(&msg);
10283 }
10284
10285 defwndproc_counter++;
10286 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
10287 defwndproc_counter--;
10288
10289 return ret;
10290 }
10291
10292 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
10293 int caret_index, int top_index, int line)
10294 {
10295 LRESULT ret;
10296
10297 /* calling an orig proc helps to avoid unnecessary message logging */
10298 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
10299 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
10300 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
10301 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
10302 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
10303 ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
10304 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
10305 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
10306 }
10307
10308 static void test_listbox_messages(void)
10309 {
10310 HWND parent, listbox;
10311 LRESULT ret;
10312
10313 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10314 100, 100, 200, 200, 0, 0, 0, NULL);
10315 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
10316 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
10317 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
10318 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
10319
10320 check_lb_state(listbox, 0, LB_ERR, 0, 0);
10321
10322 ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
10323 ok(ret == 0, "expected 0, got %ld\n", ret);
10324 ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
10325 ok(ret == 1, "expected 1, got %ld\n", ret);
10326 ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
10327 ok(ret == 2, "expected 2, got %ld\n", ret);
10328
10329 check_lb_state(listbox, 3, LB_ERR, 0, 0);
10330
10331 flush_sequence();
10332
10333 log_all_parent_messages++;
10334
10335 trace("selecting item 0\n");
10336 ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
10337 ok(ret == 0, "expected 0, got %ld\n", ret);
10338 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
10339 check_lb_state(listbox, 3, 0, 0, 0);
10340 flush_sequence();
10341
10342 trace("selecting item 1\n");
10343 ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
10344 ok(ret == 1, "expected 1, got %ld\n", ret);
10345 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
10346 check_lb_state(listbox, 3, 1, 1, 0);
10347
10348 trace("selecting item 2\n");
10349 ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
10350 ok(ret == 2, "expected 2, got %ld\n", ret);
10351 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
10352 check_lb_state(listbox, 3, 2, 2, 0);
10353
10354 trace("clicking on item 0\n");
10355 ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
10356 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10357 ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
10358 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10359 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
10360 check_lb_state(listbox, 3, 0, 0, 0);
10361 flush_sequence();
10362
10363 log_all_parent_messages--;
10364
10365 DestroyWindow(listbox);
10366 DestroyWindow(parent);
10367 }
10368
10369 START_TEST(msg)
10370 {
10371 BOOL ret;
10372 FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
10373
10374 init_procs();
10375
10376 if (!RegisterWindowClasses()) assert(0);
10377
10378 if (pSetWinEventHook)
10379 {
10380 hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
10381 GetModuleHandleA(0),
10382 win_event_proc,
10383 0,
10384 GetCurrentThreadId(),
10385 WINEVENT_INCONTEXT);
10386 assert(hEvent_hook);
10387
10388 if (pIsWinEventHookInstalled)
10389 {
10390 UINT event;
10391 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
10392 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
10393 }
10394 }
10395
10396 cbt_hook_thread_id = GetCurrentThreadId();
10397 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
10398 assert(hCBT_hook);
10399
10400 test_winevents();
10401
10402 /* Fix message sequences before removing 4 lines below */
10403 #if 1
10404 if (pUnhookWinEvent && hEvent_hook)
10405 {
10406 ret = pUnhookWinEvent(hEvent_hook);
10407 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10408 pUnhookWinEvent = 0;
10409 }
10410 hEvent_hook = 0;
10411 #endif
10412
10413 test_ShowWindow();
10414 test_PeekMessage();
10415 test_PeekMessage2();
10416 test_scrollwindowex();
10417 test_messages();
10418 test_showwindow();
10419 invisible_parent_tests();
10420 test_mdi_messages();
10421 test_button_messages();
10422 test_static_messages();
10423 test_listbox_messages();
10424 test_combobox_messages();
10425 test_wmime_keydown_message();
10426 test_paint_messages();
10427 test_interthread_messages();
10428 test_message_conversion();
10429 test_accelerators();
10430 test_timers();
10431 test_timers_no_wnd();
10432 test_set_hook();
10433 test_DestroyWindow();
10434 test_DispatchMessage();
10435 test_SendMessageTimeout();
10436 test_edit_messages();
10437 test_quit_message();
10438
10439 if (!pTrackMouseEvent)
10440 skip("TrackMouseEvent is not available\n");
10441 else
10442 test_TrackMouseEvent();
10443
10444 test_SetWindowRgn();
10445 test_sys_menu();
10446 test_dialog_messages();
10447 test_nullCallback();
10448 test_SetForegroundWindow();
10449 test_dbcs_wm_char();
10450
10451 UnhookWindowsHookEx(hCBT_hook);
10452 if (pUnhookWinEvent)
10453 {
10454 ret = pUnhookWinEvent(hEvent_hook);
10455 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10456 SetLastError(0xdeadbeef);
10457 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
10458 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10459 GetLastError() == 0xdeadbeef, /* Win9x */
10460 "unexpected error %d\n", GetLastError());
10461 }
10462 else
10463 skip("UnhookWinEvent is not available\n");
10464 }