[NTOS:KE/x64] Handle NMI vs swapgs race condition
[reactos.git] / modules / 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,2016 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 <limits.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "dbt.h"
34
35 #include "wine/test.h"
36
37 #define MDI_FIRST_CHILD_ID 2004
38
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE 0x0800
41 #define SWP_NOCLIENTMOVE 0x1000
42 #define SWP_STATECHANGED 0x8000
43
44 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
45
46 #ifndef WM_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER 0x0118
52 #endif
53
54 #define WND_PARENT_ID 1
55 #define WND_POPUP_ID 2
56 #define WND_CHILD_ID 3
57
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT 0x0131
60 #endif
61
62 #ifdef __i386__
63 #define ARCH "x86"
64 #elif defined __x86_64__
65 #define ARCH "amd64"
66 #elif defined __arm__
67 #define ARCH "arm"
68 #elif defined __aarch64__
69 #define ARCH "arm64"
70 #else
71 #define ARCH "none"
72 #endif
73
74 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
75 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
76 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
77 static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
78 static BOOL (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
79 static void (WINAPI *pReleaseActCtx)(HANDLE);
80
81 /* encoded DRAWITEMSTRUCT into an LPARAM */
82 typedef struct
83 {
84 union
85 {
86 struct
87 {
88 UINT type : 4; /* ODT_* flags */
89 UINT ctl_id : 4; /* Control ID */
90 UINT item_id : 4; /* Menu item ID */
91 UINT action : 4; /* ODA_* flags */
92 UINT state : 16; /* ODS_* flags */
93 } item;
94 LPARAM lp;
95 } u;
96 } DRAW_ITEM_STRUCT;
97
98 /* encoded MEASUREITEMSTRUCT into a WPARAM */
99 typedef struct
100 {
101 union
102 {
103 struct
104 {
105 UINT CtlType : 4;
106 UINT CtlID : 4;
107 UINT itemID : 4;
108 UINT wParam : 20;
109 } item;
110 WPARAM wp;
111 } u;
112 } MEASURE_ITEM_STRUCT;
113
114 static BOOL test_DestroyWindow_flag;
115 static BOOL test_context_menu;
116 static HWINEVENTHOOK hEvent_hook;
117 static HHOOK hKBD_hook;
118 static HHOOK hCBT_hook;
119 static DWORD cbt_hook_thread_id;
120
121 static const WCHAR testWindowClassW[] =
122 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
123
124 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
125
126 /*
127 FIXME: add tests for these
128 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
129 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
130 WS_THICKFRAME: thick border
131 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
132 WS_BORDER (default for overlapped windows): single black border
133 none (default for child (and popup?) windows): no border
134 */
135
136 typedef enum {
137 sent=0x1,
138 posted=0x2,
139 parent=0x4,
140 wparam=0x8,
141 lparam=0x10,
142 defwinproc=0x20,
143 beginpaint=0x40,
144 optional=0x80,
145 hook=0x100,
146 winevent_hook=0x200,
147 kbd_hook=0x400
148 } msg_flags_t;
149
150 struct message {
151 UINT message; /* the WM_* code */
152 msg_flags_t flags; /* message props */
153 WPARAM wParam; /* expected value of wParam */
154 LPARAM lParam; /* expected value of lParam */
155 WPARAM wp_mask; /* mask for wParam checks */
156 LPARAM lp_mask; /* mask for lParam checks */
157 };
158
159 struct recvd_message {
160 UINT message; /* the WM_* code */
161 msg_flags_t flags; /* message props */
162 HWND hwnd; /* window that received the message */
163 WPARAM wParam; /* expected value of wParam */
164 LPARAM lParam; /* expected value of lParam */
165 int line; /* source line where logged */
166 const char *descr; /* description for trace output */
167 char output[512]; /* trace output */
168 };
169
170 /* Empty message sequence */
171 static const struct message WmEmptySeq[] =
172 {
173 { 0 }
174 };
175 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
176 static const struct message WmCreateOverlappedSeq[] = {
177 { HCBT_CREATEWND, hook },
178 { WM_GETMINMAXINFO, sent },
179 { WM_NCCREATE, sent },
180 { WM_NCCALCSIZE, sent|wparam, 0 },
181 { 0x0093, sent|defwinproc|optional },
182 { 0x0094, sent|defwinproc|optional },
183 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
184 { WM_CREATE, sent },
185 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
186 { 0 }
187 };
188 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
189 * for a not visible overlapped window.
190 */
191 static const struct message WmSWP_ShowOverlappedSeq[] = {
192 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
193 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
194 { WM_NCPAINT, sent|wparam|optional, 1 },
195 { WM_GETTEXT, sent|defwinproc|optional },
196 { WM_ERASEBKGND, sent|optional },
197 { HCBT_ACTIVATE, hook },
198 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
199 { WM_NOTIFYFORMAT, sent|optional },
200 { WM_QUERYUISTATE, sent|optional },
201 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
202 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
203 { WM_ACTIVATEAPP, sent|wparam, 1 },
204 { WM_NCACTIVATE, sent },
205 { WM_GETTEXT, sent|defwinproc|optional },
206 { WM_ACTIVATE, sent|wparam, 1 },
207 { HCBT_SETFOCUS, hook },
208 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
209 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
210 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
211 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
212 { WM_GETTEXT, sent|optional },
213 { WM_NCPAINT, sent|wparam|optional, 1 },
214 { WM_GETTEXT, sent|defwinproc|optional },
215 { WM_ERASEBKGND, sent|optional },
216 /* Win9x adds SWP_NOZORDER below */
217 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
218 { WM_GETTEXT, sent|optional },
219 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
220 { WM_NCPAINT, sent|wparam|optional, 1 },
221 { WM_ERASEBKGND, sent|optional },
222 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
223 { WM_SYNCPAINT, sent|optional },
224 { WM_GETTITLEBARINFOEX, sent|optional },
225 { WM_PAINT, sent|optional },
226 { WM_NCPAINT, sent|beginpaint|optional },
227 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
228 { WM_ERASEBKGND, sent|beginpaint|optional },
229 { 0 }
230 };
231 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
232 * for a visible overlapped window.
233 */
234 static const struct message WmSWP_HideOverlappedSeq[] = {
235 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
236 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
237 { HCBT_ACTIVATE, hook|optional },
238 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
239 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
240 { WM_NCACTIVATE, sent|optional },
241 { WM_ACTIVATE, sent|optional },
242 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
243 { 0 }
244 };
245
246 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
247 * for a visible overlapped window.
248 */
249 static const struct message WmSWP_ResizeSeq[] = {
250 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
251 { WM_GETMINMAXINFO, sent|defwinproc },
252 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
253 { WM_NCPAINT, sent|optional },
254 { WM_GETTEXT, sent|defwinproc|optional },
255 { WM_ERASEBKGND, sent|optional },
256 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
257 { WM_SIZE, sent|defwinproc|optional },
258 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
259 { WM_NCPAINT, sent|optional },
260 { WM_GETTEXT, sent|defwinproc|optional },
261 { WM_ERASEBKGND, sent|optional },
262 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
263 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
264 { 0 }
265 };
266
267 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
268 * for a visible popup window.
269 */
270 static const struct message WmSWP_ResizePopupSeq[] = {
271 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
272 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
273 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
274 { WM_NCPAINT, sent|optional },
275 { WM_GETTEXT, sent|defwinproc|optional },
276 { WM_ERASEBKGND, sent|optional },
277 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
278 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
279 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
280 { WM_NCPAINT, sent|optional },
281 { WM_GETTEXT, sent|defwinproc|optional },
282 { WM_ERASEBKGND, sent|optional },
283 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
284 { 0 }
285 };
286
287 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
288 * for a visible overlapped window.
289 */
290 static const struct message WmSWP_MoveSeq[] = {
291 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
292 { WM_NCPAINT, sent|optional },
293 { WM_GETTEXT, sent|defwinproc|optional },
294 { WM_ERASEBKGND, sent|optional },
295 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
296 { WM_MOVE, sent|defwinproc|wparam, 0 },
297 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
298 { 0 }
299 };
300 /* Resize with SetWindowPos(SWP_NOZORDER)
301 * for a visible overlapped window
302 * SWP_NOZORDER is stripped by the logging code
303 */
304 static const struct message WmSWP_ResizeNoZOrder[] = {
305 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
306 { WM_GETMINMAXINFO, sent|defwinproc },
307 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
308 { WM_NCPAINT, sent|optional },
309 { WM_GETTEXT, sent|defwinproc|optional },
310 { WM_ERASEBKGND, sent|optional },
311 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
312 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
313 { WM_MOVE, sent|defwinproc|optional },
314 { WM_SIZE, sent|defwinproc|optional },
315 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
316 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
317 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
318 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
319 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
320 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
321 { 0 }
322 };
323
324 /* Switch visible mdi children */
325 static const struct message WmSwitchChild[] = {
326 /* Switch MDI child */
327 { WM_MDIACTIVATE, sent },/* in the MDI client */
328 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
329 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
330 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
331 /* Deactivate 2nd MDI child */
332 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
333 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
334 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
335 /* Preparing for maximize and maximize the 1st MDI child */
336 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
337 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
338 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
339 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
340 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
341 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
342 /* Lock redraw 2nd MDI child */
343 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
344 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
345 /* Restore 2nd MDI child */
346 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
347 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
348 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
349 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
350 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
351 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
352 /* Redraw 2nd MDI child */
353 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
354 /* Redraw MDI frame */
355 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
356 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
357 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
358 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
359 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
360 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
361 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
362 { HCBT_SETFOCUS, hook },
363 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
364 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
365 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
366 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
367 { WM_SETFOCUS, sent },/* in the MDI client */
368 { HCBT_SETFOCUS, hook },
369 { WM_KILLFOCUS, sent },/* in the MDI client */
370 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
371 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
372 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
373 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
374 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
375 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
376 { 0 }
377 };
378
379 /* Switch visible not maximized mdi children */
380 static const struct message WmSwitchNotMaximizedChild[] = {
381 /* Switch not maximized MDI child */
382 { WM_MDIACTIVATE, sent },/* in the MDI client */
383 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
384 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
385 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
386 /* Deactivate 1st MDI child */
387 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
388 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
389 /* Activate 2nd MDI child */
390 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
391 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
392 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
393 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
394 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
395 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
396 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
397 { HCBT_SETFOCUS, hook },
398 { WM_KILLFOCUS, sent }, /* in the MDI client */
399 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
400 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
401 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
402 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
403 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
404 { 0 }
405 };
406
407
408 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
409 SWP_NOZORDER|SWP_FRAMECHANGED)
410 * for a visible overlapped window with WS_CLIPCHILDREN style set.
411 */
412 static const struct message WmSWP_FrameChanged_clip[] = {
413 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
414 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
415 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
416 { WM_GETTEXT, sent|parent|defwinproc|optional },
417 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
418 { WM_NCPAINT, sent }, /* wparam != 1 */
419 { WM_ERASEBKGND, sent },
420 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
421 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
422 { WM_PAINT, sent },
423 { 0 }
424 };
425 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
426 SWP_NOZORDER|SWP_FRAMECHANGED)
427 * for a visible overlapped window.
428 */
429 static const struct message WmSWP_FrameChangedDeferErase[] = {
430 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
431 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
432 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
433 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
434 { WM_PAINT, sent|parent|optional },
435 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
436 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
437 { WM_PAINT, sent },
438 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
439 { WM_ERASEBKGND, sent|beginpaint|optional },
440 { 0 }
441 };
442
443 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
444 SWP_NOZORDER|SWP_FRAMECHANGED)
445 * for a visible overlapped window without WS_CLIPCHILDREN style set.
446 */
447 static const struct message WmSWP_FrameChanged_noclip[] = {
448 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
449 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
450 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
451 { WM_GETTEXT, sent|parent|defwinproc|optional },
452 { WM_ERASEBKGND, sent|parent|optional },
453 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
454 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
455 { WM_PAINT, sent },
456 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
457 { WM_ERASEBKGND, sent|beginpaint|optional },
458 { 0 }
459 };
460
461 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
462 static const struct message WmShowOverlappedSeq[] = {
463 { WM_SHOWWINDOW, sent|wparam, 1 },
464 { WM_NCPAINT, sent|wparam|optional, 1 },
465 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
466 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
467 { WM_NCPAINT, sent|wparam|optional, 1 },
468 { WM_GETTEXT, sent|defwinproc|optional },
469 { WM_ERASEBKGND, sent|optional },
470 { HCBT_ACTIVATE, hook|optional },
471 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
472 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
473 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
474 { WM_NCPAINT, sent|wparam|optional, 1 },
475 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
476 { WM_NCACTIVATE, sent|wparam|optional, 1 },
477 { WM_GETTEXT, sent|defwinproc|optional },
478 { WM_ACTIVATE, sent|wparam|optional, 1 },
479 { HCBT_SETFOCUS, hook|optional },
480 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
481 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
482 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
483 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
484 { WM_GETTEXT, sent|optional },
485 { WM_NCPAINT, sent|wparam|optional, 1 },
486 { WM_GETTEXT, sent|defwinproc|optional },
487 { WM_ERASEBKGND, sent|optional },
488 /* Win9x adds SWP_NOZORDER below */
489 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
490 { WM_NCCALCSIZE, sent|optional },
491 { WM_GETTEXT, sent|optional },
492 { WM_NCPAINT, sent|optional },
493 { WM_ERASEBKGND, sent|optional },
494 { WM_SYNCPAINT, sent|optional },
495 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
496 * messages. Does that mean that CreateWindow doesn't set initial
497 * window dimensions for overlapped windows?
498 */
499 { WM_SIZE, sent },
500 { WM_MOVE, sent },
501 #endif
502 { WM_PAINT, sent|optional },
503 { WM_NCPAINT, sent|beginpaint|optional },
504 { 0 }
505 };
506 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
507 static const struct message WmShowMaxOverlappedSeq[] = {
508 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
509 { WM_GETMINMAXINFO, sent },
510 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
511 { WM_GETMINMAXINFO, sent|defwinproc },
512 { WM_NCCALCSIZE, sent|wparam, TRUE },
513 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
514 { HCBT_ACTIVATE, hook|optional },
515 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
516 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
517 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
518 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
519 { WM_NCACTIVATE, sent|wparam|optional, 1 },
520 { WM_GETTEXT, sent|defwinproc|optional },
521 { WM_ACTIVATE, sent|wparam|optional, 1 },
522 { HCBT_SETFOCUS, hook|optional },
523 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
524 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
525 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
526 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
527 { WM_GETTEXT, sent|optional },
528 { WM_NCPAINT, sent|wparam|optional, 1 },
529 { WM_GETTEXT, sent|defwinproc|optional },
530 { WM_ERASEBKGND, sent|optional },
531 /* Win9x adds SWP_NOZORDER below */
532 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
533 { WM_MOVE, sent|defwinproc },
534 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
535 { WM_GETTEXT, sent|optional },
536 { WM_NCCALCSIZE, sent|optional },
537 { WM_NCPAINT, sent|optional },
538 { WM_ERASEBKGND, sent|optional },
539 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
540 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
541 { WM_SYNCPAINT, sent|optional },
542 { WM_GETTITLEBARINFOEX, sent|optional },
543 { WM_PAINT, sent|optional },
544 { WM_NCPAINT, sent|beginpaint|optional },
545 { WM_ERASEBKGND, sent|beginpaint|optional },
546 { 0 }
547 };
548 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
549 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
550 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
551 { WM_GETTEXT, sent|optional },
552 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
553 { WM_GETMINMAXINFO, sent|defwinproc },
554 { WM_NCCALCSIZE, sent|wparam, TRUE },
555 { WM_NCPAINT, sent|optional },
556 { WM_GETTEXT, sent|defwinproc|optional },
557 { WM_ERASEBKGND, sent|optional },
558 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
559 { WM_MOVE, sent|defwinproc|optional },
560 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
561 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
562 { WM_NCPAINT, sent|optional },
563 { WM_ERASEBKGND, sent|optional },
564 { WM_PAINT, sent|optional },
565 { WM_GETTITLEBARINFOEX, sent|optional },
566 { WM_NCPAINT, sent|beginpaint|optional },
567 { WM_ERASEBKGND, sent|beginpaint|optional },
568 { WM_SYNCPAINT, sent|optional },
569 { 0 }
570 };
571 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
572 static const struct message WmShowRestoreMinOverlappedSeq[] = {
573 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
574 { WM_QUERYOPEN, sent|optional },
575 { WM_GETTEXT, sent|optional },
576 { WM_NCACTIVATE, sent|wparam|optional, 1 },
577 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
578 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
579 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
580 { WM_MOVE, sent|optional },
581 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
582 { WM_GETTEXT, sent|optional },
583 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
584 { WM_GETMINMAXINFO, sent|defwinproc|optional },
585 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
586 { HCBT_ACTIVATE, hook|optional },
587 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
588 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
589 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
590 { WM_NCACTIVATE, sent|wparam|optional, 1 },
591 { WM_GETTEXT, sent|defwinproc|optional },
592 { WM_ACTIVATE, sent|wparam|optional, 1 },
593 { HCBT_SETFOCUS, hook|optional },
594 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
595 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
596 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
597 { WM_GETTEXT, sent|optional },
598 { WM_NCPAINT, sent|wparam|optional, 1 },
599 { WM_GETTEXT, sent|defwinproc|optional },
600 { WM_ERASEBKGND, sent },
601 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
602 { WM_MOVE, sent|defwinproc },
603 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
604 { HCBT_SETFOCUS, hook|optional },
605 { WM_SETFOCUS, sent|wparam|optional, 0 },
606 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
607 { WM_NCPAINT, sent|wparam|optional, 1 },
608 { WM_ERASEBKGND, sent|optional },
609 { HCBT_SETFOCUS, hook|optional },
610 { WM_SETFOCUS, sent|wparam|optional, 0 },
611 { WM_ACTIVATE, sent|wparam, 1 },
612 { WM_GETTEXT, sent|optional },
613 { WM_PAINT, sent|optional },
614 { WM_GETTITLEBARINFOEX, sent|optional },
615 { WM_NCPAINT, sent|beginpaint|optional },
616 { WM_ERASEBKGND, sent|beginpaint|optional },
617 { 0 }
618 };
619 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
620 static const struct message WmShowMinOverlappedSeq[] = {
621 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
622 { HCBT_SETFOCUS, hook|optional },
623 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
624 { WM_KILLFOCUS, sent|optional },
625 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
626 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
627 { WM_GETTEXT, sent|optional },
628 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
629 { WM_GETMINMAXINFO, sent|defwinproc },
630 { WM_NCCALCSIZE, sent|wparam, TRUE },
631 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
632 { WM_NCPAINT, sent|optional },
633 { WM_GETTEXT, sent|defwinproc|optional },
634 { WM_WINDOWPOSCHANGED, sent },
635 { WM_MOVE, sent|defwinproc },
636 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
637 { WM_NCCALCSIZE, sent|optional },
638 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
639 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
640 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
641 { WM_NCACTIVATE, sent|wparam|optional, 0 },
642 { WM_GETTEXT, sent|defwinproc|optional },
643 { WM_ACTIVATE, sent|optional },
644 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
645
646 /* Vista sometimes restores the window right away... */
647 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
648 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
649 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
650 { WM_QUERYOPEN, sent|optional },
651 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
652 { WM_GETMINMAXINFO, sent|optional|defwinproc },
653 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
654 { HCBT_ACTIVATE, hook|optional },
655 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
656 { WM_NCACTIVATE, sent|optional },
657 { WM_GETTEXT, sent|optional },
658 { WM_ACTIVATE, sent|optional|wparam, 1 },
659 { HCBT_SETFOCUS, hook|optional },
660 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
661 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
662 { WM_SETFOCUS, sent|optional },
663 { WM_NCPAINT, sent|optional },
664 { WM_GETTEXT, sent|defwinproc|optional },
665 { WM_ERASEBKGND, sent|optional },
666 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
667 { WM_MOVE, sent|defwinproc|optional },
668 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
669 { WM_ACTIVATE, sent|optional|wparam, 1 },
670 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
671 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
672
673 { WM_PAINT, sent|optional },
674 { WM_NCPAINT, sent|beginpaint|optional },
675 { WM_ERASEBKGND, sent|beginpaint|optional },
676 { 0 }
677 };
678 /* ShowWindow(SW_HIDE) for a visible overlapped window */
679 static const struct message WmHideOverlappedSeq[] = {
680 { WM_SHOWWINDOW, sent|wparam, 0 },
681 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
682 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
683 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
684 { WM_SIZE, sent|optional }, /* XP doesn't send it */
685 { WM_MOVE, sent|optional }, /* XP doesn't send it */
686 { WM_NCACTIVATE, sent|wparam|optional, 0 },
687 { WM_ACTIVATE, sent|wparam|optional, 0 },
688 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
689 { HCBT_SETFOCUS, hook|optional },
690 { WM_KILLFOCUS, sent|wparam|optional, 0 },
691 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
692 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
693 { 0 }
694 };
695 /* DestroyWindow for a visible overlapped window */
696 static const struct message WmDestroyOverlappedSeq[] = {
697 { HCBT_DESTROYWND, hook },
698 { 0x0090, sent|optional },
699 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
700 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
701 { 0x0090, sent|optional },
702 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
703 { WM_NCACTIVATE, sent|optional|wparam, 0 },
704 { WM_ACTIVATE, sent|optional },
705 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
706 { WM_KILLFOCUS, sent|optional|wparam, 0 },
707 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
708 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
709 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
710 { WM_DESTROY, sent },
711 { WM_NCDESTROY, sent },
712 { 0 }
713 };
714 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
715 static const struct message WmCreateMaxPopupSeq[] = {
716 { HCBT_CREATEWND, hook },
717 { WM_NCCREATE, sent },
718 { WM_NCCALCSIZE, sent|wparam, 0 },
719 { WM_CREATE, sent },
720 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
721 { WM_SIZE, sent|wparam, SIZE_RESTORED },
722 { WM_MOVE, sent },
723 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
724 { WM_GETMINMAXINFO, sent },
725 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
726 { WM_NCCALCSIZE, sent|wparam, TRUE },
727 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
728 { WM_MOVE, sent|defwinproc },
729 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
730 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
731 { WM_SHOWWINDOW, sent|wparam, 1 },
732 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
733 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
734 { HCBT_ACTIVATE, hook },
735 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
736 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
737 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
738 { WM_NCPAINT, sent|wparam|optional, 1 },
739 { WM_ERASEBKGND, sent|optional },
740 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
741 { WM_ACTIVATEAPP, sent|wparam, 1 },
742 { WM_NCACTIVATE, sent },
743 { WM_ACTIVATE, sent|wparam, 1 },
744 { HCBT_SETFOCUS, hook },
745 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
746 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
747 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
748 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
749 { WM_GETTEXT, sent|optional },
750 { WM_SYNCPAINT, sent|wparam|optional, 4 },
751 { WM_NCPAINT, sent|wparam|optional, 1 },
752 { WM_ERASEBKGND, sent|optional },
753 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
754 { WM_ERASEBKGND, sent|defwinproc|optional },
755 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
756 { 0 }
757 };
758 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
759 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
760 { HCBT_CREATEWND, hook },
761 { WM_NCCREATE, sent },
762 { WM_NCCALCSIZE, sent|wparam, 0 },
763 { WM_CREATE, sent },
764 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
765 { WM_SIZE, sent|wparam, SIZE_RESTORED },
766 { WM_MOVE, sent },
767 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
768 { WM_GETMINMAXINFO, sent },
769 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
770 { WM_NCCALCSIZE, sent|wparam, TRUE },
771 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
772 { WM_MOVE, sent|defwinproc },
773 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
774 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
775 { 0 }
776 };
777 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
778 static const struct message WmShowMaxPopupResizedSeq[] = {
779 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
780 { WM_GETMINMAXINFO, sent },
781 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
782 { WM_NCCALCSIZE, sent|wparam, TRUE },
783 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
784 { HCBT_ACTIVATE, hook },
785 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
786 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
787 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
788 { WM_NCPAINT, sent|wparam|optional, 1 },
789 { WM_ERASEBKGND, sent|optional },
790 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
791 { WM_ACTIVATEAPP, sent|wparam, 1 },
792 { WM_NCACTIVATE, sent },
793 { WM_ACTIVATE, sent|wparam, 1 },
794 { HCBT_SETFOCUS, hook },
795 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
796 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
797 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
798 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
799 { WM_GETTEXT, sent|optional },
800 { WM_NCPAINT, sent|wparam|optional, 1 },
801 { WM_ERASEBKGND, sent|optional },
802 { WM_WINDOWPOSCHANGED, sent },
803 /* WinNT4.0 sends WM_MOVE */
804 { WM_MOVE, sent|defwinproc|optional },
805 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
806 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
807 { 0 }
808 };
809 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
810 static const struct message WmShowMaxPopupSeq[] = {
811 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
812 { WM_GETMINMAXINFO, sent },
813 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
814 { WM_NCCALCSIZE, sent|wparam, TRUE },
815 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
816 { HCBT_ACTIVATE, hook },
817 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
818 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
819 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
820 { WM_NCPAINT, sent|wparam|optional, 1 },
821 { WM_ERASEBKGND, sent|optional },
822 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
823 { WM_ACTIVATEAPP, sent|wparam, 1 },
824 { WM_NCACTIVATE, sent },
825 { WM_ACTIVATE, sent|wparam, 1 },
826 { HCBT_SETFOCUS, hook },
827 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
828 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
829 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
830 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
831 { WM_GETTEXT, sent|optional },
832 { WM_SYNCPAINT, sent|wparam|optional, 4 },
833 { WM_NCPAINT, sent|wparam|optional, 1 },
834 { WM_ERASEBKGND, sent|optional },
835 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
836 { WM_ERASEBKGND, sent|defwinproc|optional },
837 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
838 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
839 { WM_SIZE, sent|defwinproc|optional },
840 { 0 }
841 };
842 /* CreateWindow(WS_VISIBLE) for popup window */
843 static const struct message WmCreatePopupSeq[] = {
844 { HCBT_CREATEWND, hook },
845 { WM_NCCREATE, sent },
846 { WM_NCCALCSIZE, sent|wparam, 0 },
847 { WM_CREATE, sent },
848 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
849 { WM_SIZE, sent|wparam, SIZE_RESTORED },
850 { WM_MOVE, sent },
851 { WM_SHOWWINDOW, sent|wparam, 1 },
852 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
853 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
854 { HCBT_ACTIVATE, hook },
855 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
856 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
857 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
858 { WM_NCPAINT, sent|wparam|optional, 1 },
859 { WM_ERASEBKGND, sent|optional },
860 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
861 { WM_ACTIVATEAPP, sent|wparam, 1 },
862 { WM_NCACTIVATE, sent },
863 { WM_ACTIVATE, sent|wparam, 1 },
864 { HCBT_SETFOCUS, hook },
865 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
866 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
867 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
868 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
869 { WM_GETTEXT, sent|optional },
870 { WM_SYNCPAINT, sent|wparam|optional, 4 },
871 { WM_NCPAINT, sent|wparam|optional, 1 },
872 { WM_ERASEBKGND, sent|optional },
873 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
874 { 0 }
875 };
876 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
877 static const struct message WmShowVisMaxPopupSeq[] = {
878 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
879 { WM_GETMINMAXINFO, sent },
880 { WM_GETTEXT, sent|optional },
881 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
882 { WM_GETTEXT, sent|optional },
883 { WM_NCCALCSIZE, sent|wparam, TRUE },
884 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
885 { WM_NCPAINT, sent|wparam|optional, 1 },
886 { WM_ERASEBKGND, sent|optional },
887 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
888 { WM_MOVE, sent|defwinproc },
889 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
890 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
891 { 0 }
892 };
893 /* CreateWindow (for a child popup window, not initially visible) */
894 static const struct message WmCreateChildPopupSeq[] = {
895 { HCBT_CREATEWND, hook },
896 { WM_NCCREATE, sent },
897 { WM_NCCALCSIZE, sent|wparam, 0 },
898 { WM_CREATE, sent },
899 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
900 { WM_SIZE, sent|wparam, SIZE_RESTORED },
901 { WM_MOVE, sent },
902 { 0 }
903 };
904 /* CreateWindow (for a popup window, not initially visible,
905 * which sets WS_VISIBLE in WM_CREATE handler)
906 */
907 static const struct message WmCreateInvisiblePopupSeq[] = {
908 { HCBT_CREATEWND, hook },
909 { WM_NCCREATE, sent },
910 { WM_NCCALCSIZE, sent|wparam, 0 },
911 { WM_CREATE, sent },
912 { WM_STYLECHANGING, sent },
913 { WM_STYLECHANGED, sent },
914 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
915 { WM_SIZE, sent|wparam, SIZE_RESTORED },
916 { WM_MOVE, sent },
917 { 0 }
918 };
919 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
920 * for a popup window with WS_VISIBLE style set
921 */
922 static const struct message WmShowVisiblePopupSeq_2[] = {
923 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
924 { 0 }
925 };
926 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
927 * for a popup window with WS_VISIBLE style set
928 */
929 static const struct message WmShowVisiblePopupSeq_3[] = {
930 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
931 { HCBT_ACTIVATE, hook },
932 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
933 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
934 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
935 { WM_NCACTIVATE, sent },
936 { WM_ACTIVATE, sent|wparam, 1 },
937 { HCBT_SETFOCUS, hook },
938 { WM_KILLFOCUS, sent|parent },
939 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
940 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
941 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
942 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
943 { WM_SETFOCUS, sent|defwinproc },
944 { WM_GETTEXT, sent|optional },
945 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
946 { 0 }
947 };
948 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
949 */
950 static const struct message WmShowPopupExtremeLocationSeq[] = {
951 { HCBT_CREATEWND, hook },
952 { WM_NCCREATE, sent },
953 { WM_NCCALCSIZE, sent|wparam, 0 },
954 { WM_CREATE, sent },
955 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
956 { WM_SIZE, sent|wparam, SIZE_RESTORED },
957 { WM_MOVE, sent },
958 { WM_SHOWWINDOW, sent|wparam, 1 },
959 { WM_WINDOWPOSCHANGING, sent },
960 { HCBT_ACTIVATE, hook },
961 { WM_WINDOWPOSCHANGING, sent|optional },
962 { WM_QUERYNEWPALETTE, sent|optional },
963 { WM_ACTIVATEAPP, sent },
964 { WM_NCACTIVATE, sent },
965 { WM_ACTIVATE, sent },
966 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
967 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
968 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
969 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
970 { HCBT_SETFOCUS, hook },
971 { WM_SETFOCUS, sent|defwinproc },
972 { WM_NCPAINT, sent|wparam, 1 },
973 { WM_ERASEBKGND, sent },
974 { WM_WINDOWPOSCHANGED, sent },
975 /* occasionally received on test machines */
976 { WM_NCPAINT, sent|optional },
977 { WM_ERASEBKGND, sent|optional },
978 { 0 }
979 };
980 /* CreateWindow (for a popup window with WS_VISIBLE style set)
981 */
982 static const struct message WmShowPopupFirstDrawSeq_1[] = {
983 { HCBT_CREATEWND, hook },
984 { WM_NCCREATE, sent },
985 { WM_NCCALCSIZE, sent|wparam, 0 },
986 { WM_CREATE, sent },
987 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
988 { WM_SIZE, sent|wparam, SIZE_RESTORED },
989 { WM_MOVE, sent },
990 { WM_SHOWWINDOW, sent|wparam, 1 },
991 { WM_WINDOWPOSCHANGING, sent },
992 { HCBT_ACTIVATE, hook },
993 { WM_WINDOWPOSCHANGING, sent|optional },
994 { WM_QUERYNEWPALETTE, sent|optional },
995 { WM_ACTIVATEAPP, sent },
996 { WM_NCACTIVATE, sent },
997 { WM_ACTIVATE, sent },
998 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
999 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1000 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1001 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1002 { HCBT_SETFOCUS, hook },
1003 { WM_SETFOCUS, sent|defwinproc },
1004 { WM_NCPAINT, sent|wparam, 1 },
1005 { WM_ERASEBKGND, sent },
1006 { WM_WINDOWPOSCHANGED, sent },
1007 { WM_PAINT, sent },
1008 /* occasionally received on test machines */
1009 { WM_NCPAINT, sent|beginpaint|optional },
1010 { WM_ERASEBKGND, sent|beginpaint|optional },
1011 { 0 }
1012 };
1013 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1014 */
1015 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1016 { HCBT_CREATEWND, hook },
1017 { WM_NCCREATE, sent },
1018 { WM_NCCALCSIZE, sent|wparam, 0 },
1019 { WM_CREATE, sent },
1020 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1021 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1022 { WM_MOVE, sent },
1023 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1024 { WM_GETMINMAXINFO, sent },
1025 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1026 { WM_NCCALCSIZE, sent|wparam, TRUE },
1027 { HCBT_ACTIVATE, hook },
1028 { WM_WINDOWPOSCHANGING, sent|optional },
1029 { WM_NCPAINT, sent|optional|wparam, 1 },
1030 { WM_ERASEBKGND, sent|optional },
1031 { WM_WINDOWPOSCHANGED, sent|optional },
1032 { WM_QUERYNEWPALETTE, sent|optional },
1033 { WM_ACTIVATEAPP, sent },
1034 { WM_NCACTIVATE, sent },
1035 { WM_ACTIVATE, sent },
1036 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1037 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1038 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1039 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1040 { HCBT_SETFOCUS, hook },
1041 { WM_SETFOCUS, sent|defwinproc },
1042 { WM_NCPAINT, sent|wparam, 1 },
1043 { WM_ERASEBKGND, sent },
1044 { WM_WINDOWPOSCHANGED, sent|optional },
1045 { WM_MOVE, sent|defwinproc },
1046 { WM_SIZE, sent|defwinproc, 0 },
1047 { WM_PAINT, sent},
1048 /* occasionally received on test machines */
1049 { WM_NCPAINT, sent|beginpaint|optional },
1050 { WM_ERASEBKGND, sent|beginpaint|optional },
1051 { 0 }
1052 };
1053 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1054 { HCBT_CREATEWND, hook },
1055 { WM_NCCREATE, sent },
1056 { WM_NCCALCSIZE, sent|wparam, 0 },
1057 { WM_CREATE, sent },
1058 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1059 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1060 { WM_MOVE, sent },
1061 { WM_WINDOWPOSCHANGING, sent },
1062 { HCBT_ACTIVATE, hook },
1063 { WM_WINDOWPOSCHANGING, sent|optional },
1064 { WM_QUERYNEWPALETTE, sent|optional },
1065 { WM_ACTIVATEAPP, sent },
1066 { WM_NCACTIVATE, sent },
1067 { WM_ACTIVATE, sent },
1068 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1069 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1070 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1071 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1072 { HCBT_SETFOCUS, hook },
1073 { WM_SETFOCUS, sent|defwinproc },
1074 { WM_NCPAINT, sent|wparam, 1 },
1075 { WM_ERASEBKGND, sent },
1076 { WM_WINDOWPOSCHANGED, sent },
1077 { WM_MOVE, sent|defwinproc },
1078 { 0 }
1079 };
1080 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1081 { HCBT_CREATEWND, hook },
1082 { WM_NCCREATE, sent },
1083 { WM_NCCALCSIZE, sent|wparam, 0 },
1084 { WM_CREATE, sent },
1085 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1086 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1087 { WM_MOVE, sent },
1088 { WM_WINDOWPOSCHANGING, sent },
1089 { HCBT_ACTIVATE, hook },
1090 { WM_QUERYNEWPALETTE, sent|optional },
1091 { WM_WINDOWPOSCHANGING, sent|optional },
1092 { WM_ACTIVATEAPP, sent },
1093 { WM_NCACTIVATE, sent },
1094 { WM_ACTIVATE, sent },
1095 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1096 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1097 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1098 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1099 { HCBT_SETFOCUS, hook },
1100 { WM_SETFOCUS, sent|defwinproc },
1101 { WM_WINDOWPOSCHANGED, sent },
1102 { WM_MOVE, sent|defwinproc },
1103 { 0 }
1104 };
1105 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1106 { HCBT_CREATEWND, hook },
1107 { WM_NCCREATE, sent },
1108 { WM_NCCALCSIZE, sent|wparam, 0 },
1109 { WM_CREATE, sent },
1110 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1111 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1112 { WM_MOVE, sent },
1113 { HCBT_ACTIVATE, hook|optional },
1114 /* Probably shouldn't happen, but not part of this test */
1115 { WM_QUERYNEWPALETTE, sent|optional },
1116 { WM_ACTIVATEAPP, sent|optional },
1117 { WM_NCACTIVATE, sent|optional },
1118 { WM_ACTIVATE, sent|optional },
1119 { HCBT_SETFOCUS, hook|optional },
1120 { WM_SETFOCUS, sent|defwinproc|optional },
1121 { 0 }
1122 };
1123 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1124 { HCBT_CREATEWND, hook },
1125 { WM_NCCREATE, sent },
1126 { WM_NCCALCSIZE, sent|wparam, 0 },
1127 { WM_CREATE, sent },
1128 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1129 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1130 { WM_MOVE, sent },
1131 { WM_WINDOWPOSCHANGING, sent },
1132 { HCBT_ACTIVATE, hook },
1133 { WM_WINDOWPOSCHANGING, sent|optional },
1134 { WM_QUERYNEWPALETTE, sent|optional },
1135 { WM_ACTIVATEAPP, sent },
1136 { WM_NCACTIVATE, sent },
1137 { WM_ACTIVATE, sent },
1138 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1139 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1140 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1141 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1142 { HCBT_SETFOCUS, hook },
1143 { WM_SETFOCUS, sent|defwinproc },
1144 { WM_NCPAINT, sent|wparam, 1 },
1145 { WM_ERASEBKGND, sent },
1146 { WM_WINDOWPOSCHANGED, sent },
1147 { 0 }
1148 };
1149 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1150 { HCBT_CREATEWND, hook },
1151 { WM_NCCREATE, sent },
1152 { WM_NCCALCSIZE, sent|wparam, 0 },
1153 { WM_CREATE, sent },
1154 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1155 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1156 { WM_MOVE, sent },
1157 { WM_WINDOWPOSCHANGING, sent },
1158 { HCBT_ACTIVATE, hook },
1159 { WM_WINDOWPOSCHANGING, sent|optional },
1160 { WM_QUERYNEWPALETTE, sent|optional },
1161 { WM_ACTIVATEAPP, sent },
1162 { WM_NCACTIVATE, sent },
1163 { WM_ACTIVATE, sent },
1164 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1165 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1166 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1167 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1168 { HCBT_SETFOCUS, hook },
1169 { WM_SETFOCUS, sent|defwinproc },
1170 { WM_WINDOWPOSCHANGED, sent },
1171 { 0 }
1172 };
1173 static const struct message WmFirstDrawChildSeq1[] = {
1174 { 0 }
1175 };
1176 static const struct message WmFirstDrawChildSeq2[] = {
1177 { WM_NCPAINT, sent|wparam, 1 },
1178 { WM_ERASEBKGND, sent },
1179 /* occasionally received on test machines */
1180 { WM_NCPAINT, sent|optional },
1181 { WM_ERASEBKGND, sent|optional },
1182 { 0 }
1183 };
1184 /* CreateWindow (for child window, not initially visible) */
1185 static const struct message WmCreateChildSeq[] = {
1186 { HCBT_CREATEWND, hook },
1187 { WM_NCCREATE, sent },
1188 /* child is inserted into parent's child list after WM_NCCREATE returns */
1189 { WM_NCCALCSIZE, sent|wparam, 0 },
1190 { WM_CREATE, sent },
1191 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1192 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1193 { WM_MOVE, sent },
1194 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1195 { 0 }
1196 };
1197 /* CreateWindow (for maximized child window, not initially visible) */
1198 static const struct message WmCreateMaximizedChildSeq[] = {
1199 { HCBT_CREATEWND, hook },
1200 { WM_NCCREATE, sent },
1201 { WM_NCCALCSIZE, sent|wparam, 0 },
1202 { WM_CREATE, sent },
1203 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1204 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1205 { WM_MOVE, sent },
1206 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1207 { WM_GETMINMAXINFO, sent },
1208 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1209 { WM_NCCALCSIZE, sent|wparam, 1 },
1210 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1211 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1212 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1213 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1214 { 0 }
1215 };
1216 /* CreateWindow (for a child window, initially visible) */
1217 static const struct message WmCreateVisibleChildSeq[] = {
1218 { HCBT_CREATEWND, hook },
1219 { WM_NCCREATE, sent },
1220 /* child is inserted into parent's child list after WM_NCCREATE returns */
1221 { WM_NCCALCSIZE, sent|wparam, 0 },
1222 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1223 { WM_CREATE, sent },
1224 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1225 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1226 { WM_MOVE, sent },
1227 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1228 { WM_SHOWWINDOW, sent|wparam, 1 },
1229 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1230 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1231 { WM_ERASEBKGND, sent|parent|optional },
1232 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1233 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1234 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1235 { 0 }
1236 };
1237 /* ShowWindow(SW_SHOW) for a not visible child window */
1238 static const struct message WmShowChildSeq[] = {
1239 { WM_SHOWWINDOW, sent|wparam, 1 },
1240 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1241 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1242 { WM_ERASEBKGND, sent|parent|optional },
1243 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1244 { 0 }
1245 };
1246 /* ShowWindow(SW_HIDE) for a visible child window */
1247 static const struct message WmHideChildSeq[] = {
1248 { WM_SHOWWINDOW, sent|wparam, 0 },
1249 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1250 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1251 { WM_ERASEBKGND, sent|parent|optional },
1252 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1253 { 0 }
1254 };
1255 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1256 static const struct message WmHideChildSeq2[] = {
1257 { WM_SHOWWINDOW, sent|wparam, 0 },
1258 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1259 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1260 { WM_ERASEBKGND, sent|parent|optional },
1261 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1262 { 0 }
1263 };
1264 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1265 * for a not visible child window
1266 */
1267 static const struct message WmShowChildSeq_2[] = {
1268 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1269 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1270 { WM_CHILDACTIVATE, sent },
1271 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1272 { 0 }
1273 };
1274 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1275 * for a not visible child window
1276 */
1277 static const struct message WmShowChildSeq_3[] = {
1278 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1279 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1280 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1281 { 0 }
1282 };
1283 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1284 * for a visible child window with a caption
1285 */
1286 static const struct message WmShowChildSeq_4[] = {
1287 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1288 { WM_CHILDACTIVATE, sent },
1289 { 0 }
1290 };
1291 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1292 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1293 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1294 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1295 { WM_NCCALCSIZE, sent|wparam, 1 },
1296 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1297 { WM_CHILDACTIVATE, sent|optional },
1298 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1299 { WM_MOVE, sent|defwinproc },
1300 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1301 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1302 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1303 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1304 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1305 { WM_GETTEXT, sent|optional },
1306 { 0 }
1307 };
1308 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1309 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1310 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1311 { 0 }
1312 };
1313 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1314 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1315 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1316 { WM_GETMINMAXINFO, sent },
1317 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1318 { WM_NCCALCSIZE, sent|wparam, 1 },
1319 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1320 { WM_CHILDACTIVATE, sent },
1321 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1322 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1323 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1324 { 0 }
1325 };
1326 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1327 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1328 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1329 { 0 }
1330 };
1331 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1332 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1333 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1334 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1335 { WM_NCCALCSIZE, sent|wparam, 1 },
1336 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1337 { WM_CHILDACTIVATE, sent },
1338 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1339 { WM_MOVE, sent|defwinproc },
1340 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1341 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1342 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1343 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1344 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1345 { WM_GETTEXT, sent|optional },
1346 { 0 }
1347 };
1348 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1349 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1350 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1351 { 0 }
1352 };
1353 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1354 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1355 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1356 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1357 { WM_NCCALCSIZE, sent|wparam, 1 },
1358 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1359 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1360 { WM_MOVE, sent|defwinproc },
1361 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1362 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1363 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1364 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1365 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1366 { WM_GETTEXT, sent|optional },
1367 { 0 }
1368 };
1369 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1370 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1371 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1372 { 0 }
1373 };
1374 /* ShowWindow(SW_SHOW) for child with invisible parent */
1375 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1376 { WM_SHOWWINDOW, sent|wparam, 1 },
1377 { 0 }
1378 };
1379 /* ShowWindow(SW_HIDE) for child with invisible parent */
1380 static const struct message WmHideChildInvisibleParentSeq[] = {
1381 { WM_SHOWWINDOW, sent|wparam, 0 },
1382 { 0 }
1383 };
1384 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1385 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1386 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1387 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1388 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1389 { 0 }
1390 };
1391 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1392 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1393 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1394 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1395 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1396 { 0 }
1397 };
1398 /* DestroyWindow for a visible child window */
1399 static const struct message WmDestroyChildSeq[] = {
1400 { HCBT_DESTROYWND, hook },
1401 { 0x0090, sent|optional },
1402 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1403 { WM_SHOWWINDOW, sent|wparam, 0 },
1404 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1405 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1406 { WM_ERASEBKGND, sent|parent|optional },
1407 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1408 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1409 { WM_KILLFOCUS, sent },
1410 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1411 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1412 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1413 { WM_SETFOCUS, sent|parent },
1414 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1415 { WM_DESTROY, sent },
1416 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1417 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1418 { WM_NCDESTROY, sent },
1419 { 0 }
1420 };
1421 /* visible child window destroyed by thread exit */
1422 static const struct message WmExitThreadSeq[] = {
1423 { WM_NCDESTROY, sent }, /* actually in grandchild */
1424 { WM_PAINT, sent|parent },
1425 { WM_ERASEBKGND, sent|parent|beginpaint },
1426 { 0 }
1427 };
1428 /* DestroyWindow for a visible child window with invisible parent */
1429 static const struct message WmDestroyInvisibleChildSeq[] = {
1430 { HCBT_DESTROYWND, hook },
1431 { 0x0090, sent|optional },
1432 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1433 { WM_SHOWWINDOW, sent|wparam, 0 },
1434 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1435 { WM_DESTROY, sent },
1436 { WM_NCDESTROY, sent },
1437 { 0 }
1438 };
1439 /* Resizing child window with MoveWindow (32) */
1440 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1441 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1442 { WM_NCCALCSIZE, sent|wparam, 1 },
1443 { WM_ERASEBKGND, sent|parent|optional },
1444 { WM_ERASEBKGND, sent|optional },
1445 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1446 { WM_MOVE, sent|defwinproc },
1447 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1448 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1449 { 0 }
1450 };
1451 /* Creation of a custom dialog (32) */
1452 static const struct message WmCreateCustomDialogSeq[] = {
1453 { HCBT_CREATEWND, hook },
1454 { WM_GETMINMAXINFO, sent },
1455 { WM_NCCREATE, sent },
1456 { WM_NCCALCSIZE, sent|wparam, 0 },
1457 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1458 { WM_CREATE, sent },
1459 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1460 { WM_NOTIFYFORMAT, sent|optional },
1461 { WM_QUERYUISTATE, sent|optional },
1462 { WM_WINDOWPOSCHANGING, sent|optional },
1463 { WM_GETMINMAXINFO, sent|optional },
1464 { WM_NCCALCSIZE, sent|optional },
1465 { WM_WINDOWPOSCHANGED, sent|optional },
1466 { WM_SHOWWINDOW, sent|wparam, 1 },
1467 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1468 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1469 { HCBT_ACTIVATE, hook },
1470 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1471
1472
1473 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1474
1475 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1476
1477 { WM_NCACTIVATE, sent },
1478 { WM_GETTEXT, sent|optional|defwinproc },
1479 { WM_GETTEXT, sent|optional|defwinproc },
1480 { WM_GETTEXT, sent|optional|defwinproc },
1481 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1482 { WM_ACTIVATE, sent|wparam, 1 },
1483 { WM_GETTEXT, sent|optional },
1484 { WM_KILLFOCUS, sent|parent },
1485 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1486 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1487 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1488 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1489 { WM_SETFOCUS, sent },
1490 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1491 { WM_NCPAINT, sent|wparam, 1 },
1492 { WM_GETTEXT, sent|optional|defwinproc },
1493 { WM_GETTEXT, sent|optional|defwinproc },
1494 { WM_ERASEBKGND, sent },
1495 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1496 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1497 { WM_GETTEXT, sent|optional },
1498 { WM_GETTEXT, sent|optional },
1499 { WM_NCCALCSIZE, sent|optional },
1500 { WM_NCPAINT, sent|optional },
1501 { WM_GETTEXT, sent|optional|defwinproc },
1502 { WM_GETTEXT, sent|optional|defwinproc },
1503 { WM_ERASEBKGND, sent|optional },
1504 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1505 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1506 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1507 { WM_MOVE, sent },
1508 { 0 }
1509 };
1510 /* Calling EndDialog for a custom dialog (32) */
1511 static const struct message WmEndCustomDialogSeq[] = {
1512 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1513 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1514 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1515 { WM_GETTEXT, sent|optional },
1516 { HCBT_ACTIVATE, hook },
1517 { WM_NCACTIVATE, sent|wparam, 0 },
1518 { WM_GETTEXT, sent|optional|defwinproc },
1519 { WM_GETTEXT, sent|optional|defwinproc },
1520 { WM_ACTIVATE, sent|wparam, 0 },
1521 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1522 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1523 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1524 { WM_GETTEXT, sent|optional|defwinproc },
1525 { WM_GETTEXT, sent|optional|defwinproc },
1526 { HCBT_SETFOCUS, hook },
1527 { WM_KILLFOCUS, sent },
1528 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1529 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1530 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1531 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1532 { WM_SETFOCUS, sent|parent|defwinproc },
1533 { 0 }
1534 };
1535 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1536 static const struct message WmShowCustomDialogSeq[] = {
1537 { WM_SHOWWINDOW, sent|wparam, 1 },
1538 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1539 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1540 { HCBT_ACTIVATE, hook },
1541 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1542
1543 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1544
1545 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1546 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1547 { WM_NCACTIVATE, sent },
1548 { WM_ACTIVATE, sent|wparam, 1 },
1549 { WM_GETTEXT, sent|optional },
1550
1551 { WM_KILLFOCUS, sent|parent },
1552 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1553 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1554 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1555 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1556 { WM_SETFOCUS, sent },
1557 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1558 { WM_NCPAINT, sent|wparam, 1 },
1559 { WM_ERASEBKGND, sent },
1560 { WM_CTLCOLORDLG, sent|defwinproc },
1561 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1562 { 0 }
1563 };
1564 /* Creation and destruction of a modal dialog (32) */
1565 static const struct message WmModalDialogSeq[] = {
1566 { WM_CANCELMODE, sent|parent },
1567 { HCBT_SETFOCUS, hook },
1568 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1569 { WM_KILLFOCUS, sent|parent },
1570 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1571 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1572 { WM_ENABLE, sent|parent|wparam, 0 },
1573 { HCBT_CREATEWND, hook },
1574 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1575 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1576 { WM_SETFONT, sent },
1577 { WM_INITDIALOG, sent },
1578 { WM_CHANGEUISTATE, sent|optional },
1579 { WM_UPDATEUISTATE, sent|optional },
1580 { WM_SHOWWINDOW, sent },
1581 { HCBT_ACTIVATE, hook },
1582 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1583 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1584 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1585 { WM_NCACTIVATE, sent },
1586 { WM_GETTEXT, sent|optional },
1587 { WM_ACTIVATE, sent|wparam, 1 },
1588 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1589 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1590 { WM_NCPAINT, sent|optional },
1591 { WM_GETTEXT, sent|optional },
1592 { WM_ERASEBKGND, sent|optional },
1593 { WM_CTLCOLORDLG, sent|optional },
1594 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1595 { WM_GETTEXT, sent|optional },
1596 { WM_NCCALCSIZE, sent|optional },
1597 { WM_NCPAINT, sent|optional },
1598 { WM_GETTEXT, sent|optional },
1599 { WM_ERASEBKGND, sent|optional },
1600 { WM_CTLCOLORDLG, sent|optional },
1601 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1602 { WM_PAINT, sent|optional },
1603 { WM_CTLCOLORBTN, sent|optional },
1604 { WM_GETTITLEBARINFOEX, sent|optional },
1605 { WM_ENTERIDLE, sent|parent|optional },
1606 { WM_ENTERIDLE, sent|parent|optional },
1607 { WM_ENTERIDLE, sent|parent|optional },
1608 { WM_ENTERIDLE, sent|parent|optional },
1609 { WM_ENTERIDLE, sent|parent|optional },
1610 { WM_ENTERIDLE, sent|parent|optional },
1611 { WM_ENTERIDLE, sent|parent|optional },
1612 { WM_ENTERIDLE, sent|parent|optional },
1613 { WM_ENTERIDLE, sent|parent|optional },
1614 { WM_ENTERIDLE, sent|parent|optional },
1615 { WM_ENTERIDLE, sent|parent|optional },
1616 { WM_ENTERIDLE, sent|parent|optional },
1617 { WM_ENTERIDLE, sent|parent|optional },
1618 { WM_ENTERIDLE, sent|parent|optional },
1619 { WM_ENTERIDLE, sent|parent|optional },
1620 { WM_ENTERIDLE, sent|parent|optional },
1621 { WM_ENTERIDLE, sent|parent|optional },
1622 { WM_ENTERIDLE, sent|parent|optional },
1623 { WM_ENTERIDLE, sent|parent|optional },
1624 { WM_ENTERIDLE, sent|parent|optional },
1625 { WM_TIMER, sent },
1626 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1627 { WM_ENABLE, sent|parent|wparam, 1 },
1628 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1629 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1630 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1631 { WM_GETTEXT, sent|optional },
1632 { HCBT_ACTIVATE, hook },
1633 { WM_NCACTIVATE, sent|wparam, 0 },
1634 { WM_GETTEXT, sent|optional },
1635 { WM_ACTIVATE, sent|wparam, 0 },
1636 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1637 { WM_WINDOWPOSCHANGING, sent|optional },
1638 { WM_WINDOWPOSCHANGED, sent|optional },
1639 { HCBT_SETFOCUS, hook },
1640 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1641 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1642 { WM_SETFOCUS, sent|parent|defwinproc },
1643 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1644 { HCBT_DESTROYWND, hook },
1645 { 0x0090, sent|optional },
1646 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1647 { WM_DESTROY, sent },
1648 { WM_NCDESTROY, sent },
1649 { 0 }
1650 };
1651 static const struct message WmModalDialogSeq_2[] = {
1652 { WM_CANCELMODE, sent },
1653 { HCBT_SETFOCUS, hook },
1654 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1655 { WM_KILLFOCUS, sent },
1656 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1657 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1658 { WM_ENABLE, sent|wparam, 0 },
1659 { HCBT_CREATEWND, hook },
1660 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1661 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1662 { WM_SETFONT, sent },
1663 { WM_INITDIALOG, sent },
1664 { WM_CHANGEUISTATE, sent|optional },
1665 { WM_UPDATEUISTATE, sent|optional },
1666 { WM_ENABLE, sent|wparam, 1 },
1667 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1668 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1669 { WM_CHANGEUISTATE, sent|optional },
1670 { WM_UPDATEUISTATE, sent|optional },
1671 { HCBT_DESTROYWND, hook },
1672 { 0x0090, sent|optional },
1673 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1674 { WM_DESTROY, sent },
1675 { WM_NCDESTROY, sent },
1676 { 0 }
1677 };
1678 /* SetMenu for NonVisible windows with size change*/
1679 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1680 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1681 { WM_NCCALCSIZE, sent|wparam, 1 },
1682 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1683 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1684 { WM_MOVE, sent|defwinproc },
1685 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1686 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1687 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1688 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1689 { WM_GETTEXT, sent|optional },
1690 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1691 { 0 }
1692 };
1693 /* SetMenu for NonVisible windows with no size change */
1694 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1695 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1696 { WM_NCCALCSIZE, sent|wparam, 1 },
1697 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1698 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1699 { 0 }
1700 };
1701 /* SetMenu for Visible windows with size change */
1702 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1703 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1704 { WM_NCCALCSIZE, sent|wparam, 1 },
1705 { 0x0093, sent|defwinproc|optional },
1706 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1707 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1708 { 0x0093, sent|defwinproc|optional },
1709 { 0x0093, sent|defwinproc|optional },
1710 { 0x0091, sent|defwinproc|optional },
1711 { 0x0092, sent|defwinproc|optional },
1712 { WM_GETTEXT, sent|defwinproc|optional },
1713 { WM_ERASEBKGND, sent|optional },
1714 { WM_ACTIVATE, sent|optional },
1715 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1716 { WM_MOVE, sent|defwinproc },
1717 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1718 { 0x0093, sent|optional },
1719 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1720 { 0x0093, sent|defwinproc|optional },
1721 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1722 { 0x0093, sent|defwinproc|optional },
1723 { 0x0093, sent|defwinproc|optional },
1724 { 0x0091, sent|defwinproc|optional },
1725 { 0x0092, sent|defwinproc|optional },
1726 { WM_ERASEBKGND, sent|optional },
1727 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1728 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1729 { 0 }
1730 };
1731 /* SetMenu for Visible windows with no size change */
1732 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1733 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1734 { WM_NCCALCSIZE, sent|wparam, 1 },
1735 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1736 { WM_GETTEXT, sent|defwinproc|optional },
1737 { WM_ERASEBKGND, sent|optional },
1738 { WM_ACTIVATE, sent|optional },
1739 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1740 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1741 { 0 }
1742 };
1743 /* DrawMenuBar for a visible window */
1744 static const struct message WmDrawMenuBarSeq[] =
1745 {
1746 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1747 { WM_NCCALCSIZE, sent|wparam, 1 },
1748 { 0x0093, sent|defwinproc|optional },
1749 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1750 { 0x0093, sent|defwinproc|optional },
1751 { 0x0093, sent|defwinproc|optional },
1752 { 0x0091, sent|defwinproc|optional },
1753 { 0x0092, sent|defwinproc|optional },
1754 { WM_GETTEXT, sent|defwinproc|optional },
1755 { WM_ERASEBKGND, sent|optional },
1756 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1757 { 0x0093, sent|optional },
1758 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1759 { 0 }
1760 };
1761
1762 static const struct message WmSetRedrawFalseSeq[] =
1763 {
1764 { WM_SETREDRAW, sent|wparam, 0 },
1765 { 0 }
1766 };
1767
1768 static const struct message WmSetRedrawTrueSeq[] =
1769 {
1770 { WM_SETREDRAW, sent|wparam, 1 },
1771 { 0 }
1772 };
1773
1774 static const struct message WmEnableWindowSeq_1[] =
1775 {
1776 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1777 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1778 { HCBT_SETFOCUS, hook|optional },
1779 { WM_KILLFOCUS, sent|optional },
1780 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1781 { 0 }
1782 };
1783
1784 static const struct message WmEnableWindowSeq_2[] =
1785 {
1786 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1787 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1788 { 0 }
1789 };
1790
1791 static const struct message WmEnableWindowSeq_3[] =
1792 {
1793 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1794 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1795 { 0 }
1796 };
1797
1798 static const struct message WmEnableWindowSeq_4[] =
1799 {
1800 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1801 { 0 }
1802 };
1803
1804 static const struct message WmGetScrollRangeSeq[] =
1805 {
1806 { SBM_GETRANGE, sent },
1807 { 0 }
1808 };
1809 static const struct message WmGetScrollInfoSeq[] =
1810 {
1811 { SBM_GETSCROLLINFO, sent },
1812 { 0 }
1813 };
1814 static const struct message WmSetScrollRangeSeq[] =
1815 {
1816 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1817 sends SBM_SETSCROLLINFO.
1818 */
1819 { SBM_SETSCROLLINFO, sent },
1820 { 0 }
1821 };
1822 /* SetScrollRange for a window without a non-client area */
1823 static const struct message WmSetScrollRangeHSeq_empty[] =
1824 {
1825 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1826 { 0 }
1827 };
1828 static const struct message WmSetScrollRangeVSeq_empty[] =
1829 {
1830 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1831 { 0 }
1832 };
1833 static const struct message WmSetScrollRangeHVSeq[] =
1834 {
1835 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1836 { WM_NCCALCSIZE, sent|wparam, 1 },
1837 { WM_GETTEXT, sent|defwinproc|optional },
1838 { WM_ERASEBKGND, sent|optional },
1839 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1840 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1841 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1842 { 0 }
1843 };
1844 /* SetScrollRange for a window with a non-client area */
1845 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1846 {
1847 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1848 { WM_NCCALCSIZE, sent|wparam, 1 },
1849 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1850 { WM_NCPAINT, sent|optional },
1851 { WM_STYLECHANGING, sent|defwinproc|optional },
1852 { WM_STYLECHANGED, sent|defwinproc|optional },
1853 { WM_STYLECHANGING, sent|defwinproc|optional },
1854 { WM_STYLECHANGED, sent|defwinproc|optional },
1855 { WM_STYLECHANGING, sent|defwinproc|optional },
1856 { WM_STYLECHANGED, sent|defwinproc|optional },
1857 { WM_STYLECHANGING, sent|defwinproc|optional },
1858 { WM_STYLECHANGED, sent|defwinproc|optional },
1859 { WM_GETTEXT, sent|defwinproc|optional },
1860 { WM_GETTEXT, sent|defwinproc|optional },
1861 { WM_ERASEBKGND, sent|optional },
1862 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1863 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1864 { WM_SIZE, sent|defwinproc|optional },
1865 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1866 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1867 { WM_GETTEXT, sent|optional },
1868 { WM_GETTEXT, sent|optional },
1869 { WM_GETTEXT, sent|optional },
1870 { WM_GETTEXT, sent|optional },
1871 { 0 }
1872 };
1873 /* test if we receive the right sequence of messages */
1874 /* after calling ShowWindow( SW_SHOWNA) */
1875 static const struct message WmSHOWNAChildInvisParInvis[] = {
1876 { WM_SHOWWINDOW, sent|wparam, 1 },
1877 { 0 }
1878 };
1879 static const struct message WmSHOWNAChildVisParInvis[] = {
1880 { WM_SHOWWINDOW, sent|wparam, 1 },
1881 { 0 }
1882 };
1883 static const struct message WmSHOWNAChildVisParVis[] = {
1884 { WM_SHOWWINDOW, sent|wparam, 1 },
1885 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1886 { 0 }
1887 };
1888 static const struct message WmSHOWNAChildInvisParVis[] = {
1889 { WM_SHOWWINDOW, sent|wparam, 1 },
1890 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1891 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1892 { WM_ERASEBKGND, sent|optional },
1893 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1894 { 0 }
1895 };
1896 static const struct message WmSHOWNATopVisible[] = {
1897 { WM_SHOWWINDOW, sent|wparam, 1 },
1898 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1899 { WM_NCPAINT, sent|wparam|optional, 1 },
1900 { WM_GETTEXT, sent|defwinproc|optional },
1901 { WM_ERASEBKGND, sent|optional },
1902 { WM_WINDOWPOSCHANGED, sent|optional },
1903 { 0 }
1904 };
1905 static const struct message WmSHOWNATopInvisible[] = {
1906 { WM_NOTIFYFORMAT, sent|optional },
1907 { WM_QUERYUISTATE, sent|optional },
1908 { WM_WINDOWPOSCHANGING, sent|optional },
1909 { WM_GETMINMAXINFO, sent|optional },
1910 { WM_NCCALCSIZE, sent|optional },
1911 { WM_WINDOWPOSCHANGED, sent|optional },
1912 { WM_SHOWWINDOW, sent|wparam, 1 },
1913 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1914 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1915 { WM_NCPAINT, sent|wparam|optional, 1 },
1916 { WM_GETTEXT, sent|defwinproc|optional },
1917 { WM_ERASEBKGND, sent|optional },
1918 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1919 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1920 { WM_NCPAINT, sent|wparam|optional, 1 },
1921 { WM_ERASEBKGND, sent|optional },
1922 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1923 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1924 { WM_MOVE, sent },
1925 { 0 }
1926 };
1927
1928 static const struct message WmTrackPopupMenu[] = {
1929 { HCBT_CREATEWND, hook },
1930 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1931 { WM_INITMENU, sent|lparam, 0, 0 },
1932 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1933 { 0x0093, sent|optional },
1934 { 0x0094, sent|optional },
1935 { 0x0094, sent|optional },
1936 { WM_ENTERIDLE, sent|wparam, 2 },
1937 { WM_CAPTURECHANGED, sent },
1938 { HCBT_DESTROYWND, hook },
1939 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1940 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1941 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1942 { 0 }
1943 };
1944
1945 static const struct message WmTrackPopupMenuEsc[] = {
1946 { 0 }
1947 };
1948
1949 static const struct message WmTrackPopupMenuCapture[] = {
1950 { HCBT_CREATEWND, hook },
1951 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1952 { WM_CAPTURECHANGED, sent },
1953 { WM_INITMENU, sent|lparam, 0, 0 },
1954 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1955 { 0x0093, sent|optional },
1956 { 0x0094, sent|optional },
1957 { 0x0094, sent|optional },
1958 { WM_ENTERIDLE, sent|wparam, 2 },
1959 { WM_CAPTURECHANGED, sent },
1960 { HCBT_DESTROYWND, hook },
1961 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1962 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1963 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1964 { 0 }
1965 };
1966
1967 static const struct message WmTrackPopupMenuEmpty[] = {
1968 { HCBT_CREATEWND, hook },
1969 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1970 { WM_INITMENU, sent|lparam, 0, 0 },
1971 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1972 { 0x0093, sent|optional },
1973 { 0x0094, sent|optional },
1974 { 0x0094, sent|optional },
1975 { WM_CAPTURECHANGED, sent },
1976 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1977 { HCBT_DESTROYWND, hook },
1978 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1979 { 0 }
1980 };
1981
1982 static const struct message WmTrackPopupMenuAbort[] = {
1983 { HCBT_CREATEWND, hook },
1984 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1985 { WM_INITMENU, sent|lparam, 0, 0 },
1986 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1987 { 0x0093, sent|optional },
1988 { 0x0094, sent|optional },
1989 { 0x0094, sent|optional },
1990 { WM_CAPTURECHANGED, sent },
1991 { HCBT_DESTROYWND, hook },
1992 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1993 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1994 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1995 { 0 }
1996 };
1997
1998 static BOOL after_end_dialog, test_def_id, paint_loop_done;
1999 static int sequence_cnt, sequence_size;
2000 static struct recvd_message* sequence;
2001 static int log_all_parent_messages;
2002 static CRITICAL_SECTION sequence_cs;
2003
2004 /* user32 functions */
2005 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2006 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2007 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2008 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2009 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2010 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2011 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2012 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2013 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2014 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2015 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2016 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2017 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2018 /* kernel32 functions */
2019 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2020
2021 static void init_procs(void)
2022 {
2023 HMODULE user32 = GetModuleHandleA("user32.dll");
2024 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2025
2026 #define GET_PROC(dll, func) \
2027 p ## func = (void*)GetProcAddress(dll, #func); \
2028 if(!p ## func) { \
2029 trace("GetProcAddress(%s) failed\n", #func); \
2030 }
2031
2032 GET_PROC(user32, GetAncestor)
2033 GET_PROC(user32, GetMenuInfo)
2034 GET_PROC(user32, NotifyWinEvent)
2035 GET_PROC(user32, SetMenuInfo)
2036 GET_PROC(user32, SetWinEventHook)
2037 GET_PROC(user32, TrackMouseEvent)
2038 GET_PROC(user32, UnhookWinEvent)
2039 GET_PROC(user32, GetMonitorInfoA)
2040 GET_PROC(user32, MonitorFromPoint)
2041 GET_PROC(user32, UpdateLayeredWindow)
2042 GET_PROC(user32, SetSystemTimer)
2043 GET_PROC(user32, KillSystemTimer)
2044 GET_PROC(user32, SetCoalescableTimer)
2045
2046 GET_PROC(kernel32, GetCPInfoExA)
2047
2048 #undef GET_PROC
2049 }
2050
2051 static const char *get_winpos_flags(UINT flags)
2052 {
2053 static char buffer[300];
2054
2055 buffer[0] = 0;
2056 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2057 DUMP( SWP_SHOWWINDOW );
2058 DUMP( SWP_HIDEWINDOW );
2059 DUMP( SWP_NOACTIVATE );
2060 DUMP( SWP_FRAMECHANGED );
2061 DUMP( SWP_NOCOPYBITS );
2062 DUMP( SWP_NOOWNERZORDER );
2063 DUMP( SWP_NOSENDCHANGING );
2064 DUMP( SWP_DEFERERASE );
2065 DUMP( SWP_ASYNCWINDOWPOS );
2066 DUMP( SWP_NOZORDER );
2067 DUMP( SWP_NOREDRAW );
2068 DUMP( SWP_NOSIZE );
2069 DUMP( SWP_NOMOVE );
2070 DUMP( SWP_NOCLIENTSIZE );
2071 DUMP( SWP_NOCLIENTMOVE );
2072 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2073 return buffer + 1;
2074 #undef DUMP
2075 }
2076
2077 static BOOL ignore_message( UINT message )
2078 {
2079 /* these are always ignored */
2080 return (message >= 0xc000 ||
2081 message == WM_GETICON ||
2082 message == WM_GETOBJECT ||
2083 message == WM_TIMECHANGE ||
2084 message == WM_DISPLAYCHANGE ||
2085 message == WM_DEVICECHANGE ||
2086 message == WM_DWMNCRENDERINGCHANGED);
2087 }
2088
2089 static unsigned hash_Ly_W(const WCHAR *str)
2090 {
2091 unsigned hash = 0;
2092
2093 for (; *str; str++)
2094 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2095
2096 return hash;
2097 }
2098
2099 static unsigned hash_Ly(const char *str)
2100 {
2101 unsigned hash = 0;
2102
2103 for (; *str; str++)
2104 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2105
2106 return hash;
2107 }
2108
2109 #define add_message(msg) add_message_(__LINE__,msg);
2110 static void add_message_(int line, const struct recvd_message *msg)
2111 {
2112 struct recvd_message *seq;
2113
2114 EnterCriticalSection( &sequence_cs );
2115 if (!sequence)
2116 {
2117 sequence_size = 10;
2118 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2119 }
2120 if (sequence_cnt == sequence_size)
2121 {
2122 sequence_size *= 2;
2123 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2124 }
2125 assert(sequence);
2126
2127 seq = &sequence[sequence_cnt++];
2128 seq->hwnd = msg->hwnd;
2129 seq->message = msg->message;
2130 seq->flags = msg->flags;
2131 seq->wParam = msg->wParam;
2132 seq->lParam = msg->lParam;
2133 seq->line = line;
2134 seq->descr = msg->descr;
2135 seq->output[0] = 0;
2136 LeaveCriticalSection( &sequence_cs );
2137
2138 if (msg->descr)
2139 {
2140 if (msg->flags & hook)
2141 {
2142 static const char * const CBT_code_name[10] =
2143 {
2144 "HCBT_MOVESIZE",
2145 "HCBT_MINMAX",
2146 "HCBT_QS",
2147 "HCBT_CREATEWND",
2148 "HCBT_DESTROYWND",
2149 "HCBT_ACTIVATE",
2150 "HCBT_CLICKSKIPPED",
2151 "HCBT_KEYSKIPPED",
2152 "HCBT_SYSCOMMAND",
2153 "HCBT_SETFOCUS"
2154 };
2155 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2156
2157 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2158 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2159 }
2160 else if (msg->flags & winevent_hook)
2161 {
2162 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2163 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2164 }
2165 else
2166 {
2167 switch (msg->message)
2168 {
2169 case WM_WINDOWPOSCHANGING:
2170 case WM_WINDOWPOSCHANGED:
2171 {
2172 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2173
2174 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2175 msg->descr, msg->hwnd,
2176 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2177 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2178 winpos->x, winpos->y, winpos->cx, winpos->cy,
2179 get_winpos_flags(winpos->flags) );
2180
2181 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2182 * in the high word for internal purposes
2183 */
2184 seq->wParam = winpos->flags & 0xffff;
2185 /* We are not interested in the flags that don't match under XP and Win9x */
2186 seq->wParam &= ~SWP_NOZORDER;
2187 break;
2188 }
2189
2190 case WM_DRAWITEM:
2191 {
2192 DRAW_ITEM_STRUCT di;
2193 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2194
2195 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2196 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2197 dis->itemID, dis->itemAction, dis->itemState);
2198
2199 di.u.lp = 0;
2200 di.u.item.type = dis->CtlType;
2201 di.u.item.ctl_id = dis->CtlID;
2202 if (dis->CtlType == ODT_LISTBOX ||
2203 dis->CtlType == ODT_COMBOBOX ||
2204 dis->CtlType == ODT_MENU)
2205 di.u.item.item_id = dis->itemID;
2206 di.u.item.action = dis->itemAction;
2207 di.u.item.state = dis->itemState;
2208
2209 seq->lParam = di.u.lp;
2210 break;
2211 }
2212
2213 case WM_MEASUREITEM:
2214 {
2215 MEASURE_ITEM_STRUCT mi;
2216 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2217 BOOL is_unicode_data = TRUE;
2218
2219 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2220 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2221 mis->itemID, mis->itemData);
2222
2223 if (mis->CtlType == ODT_LISTBOX)
2224 {
2225 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2226 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2227 }
2228
2229 mi.u.wp = 0;
2230 mi.u.item.CtlType = mis->CtlType;
2231 mi.u.item.CtlID = mis->CtlID;
2232 mi.u.item.itemID = mis->itemID;
2233 mi.u.item.wParam = msg->wParam;
2234 seq->wParam = mi.u.wp;
2235 if (is_unicode_data)
2236 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2237 else
2238 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2239 break;
2240 }
2241
2242 case WM_COMPAREITEM:
2243 {
2244 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2245 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2246 BOOL is_unicode_data = TRUE;
2247
2248 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2249 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2250 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2251 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2252
2253 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2254 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2255 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2256
2257 if (cis->CtlType == ODT_LISTBOX)
2258 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2259
2260 if (is_unicode_data)
2261 {
2262 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2263 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2264 }
2265 else
2266 {
2267 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2268 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2269 }
2270 break;
2271 }
2272
2273 default:
2274 if (msg->message >= 0xc000) return; /* ignore registered messages */
2275 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2276 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2277 }
2278 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2279 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2280 }
2281 }
2282 }
2283
2284 /* try to make sure pending X events have been processed before continuing */
2285 static void flush_events(void)
2286 {
2287 MSG msg;
2288 int diff = 200;
2289 int min_timeout = 100;
2290 DWORD time = GetTickCount() + diff;
2291
2292 while (diff > 0)
2293 {
2294 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2295 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2296 diff = time - GetTickCount();
2297 }
2298 }
2299
2300 static void flush_sequence(void)
2301 {
2302 EnterCriticalSection( &sequence_cs );
2303 HeapFree(GetProcessHeap(), 0, sequence);
2304 sequence = 0;
2305 sequence_cnt = sequence_size = 0;
2306 LeaveCriticalSection( &sequence_cs );
2307 }
2308
2309 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2310 {
2311 const struct recvd_message *actual = sequence;
2312 unsigned int count = 0;
2313
2314 trace_(file, line)("Failed sequence %s:\n", context );
2315 while (expected->message && actual->message)
2316 {
2317 if (actual->output[0])
2318 {
2319 if (expected->flags & hook)
2320 {
2321 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2322 count, expected->message, actual->output );
2323 }
2324 else if (expected->flags & winevent_hook)
2325 {
2326 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2327 count, expected->message, actual->output );
2328 }
2329 else if (expected->flags & kbd_hook)
2330 {
2331 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2332 count, expected->message, actual->output );
2333 }
2334 else
2335 {
2336 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2337 count, expected->message, actual->output );
2338 }
2339 }
2340
2341 if (expected->message == actual->message)
2342 {
2343 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2344 (expected->flags & optional))
2345 {
2346 /* don't match messages if their defwinproc status differs */
2347 expected++;
2348 }
2349 else
2350 {
2351 expected++;
2352 actual++;
2353 }
2354 }
2355 /* silently drop winevent messages if there is no support for them */
2356 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2357 expected++;
2358 else
2359 {
2360 expected++;
2361 actual++;
2362 }
2363 count++;
2364 }
2365
2366 /* optional trailing messages */
2367 while (expected->message && ((expected->flags & optional) ||
2368 ((expected->flags & winevent_hook) && !hEvent_hook)))
2369 {
2370 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2371 expected++;
2372 count++;
2373 }
2374
2375 if (expected->message)
2376 {
2377 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2378 return;
2379 }
2380
2381 while (actual->message && actual->output[0])
2382 {
2383 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2384 actual++;
2385 count++;
2386 }
2387 }
2388
2389 #define ok_sequence( exp, contx, todo) \
2390 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2391
2392
2393 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2394 const char *file, int line)
2395 {
2396 static const struct recvd_message end_of_sequence;
2397 const struct message *expected = expected_list;
2398 const struct recvd_message *actual;
2399 int failcount = 0, dump = 0;
2400 unsigned int count = 0;
2401
2402 add_message(&end_of_sequence);
2403
2404 actual = sequence;
2405
2406 while (expected->message && actual->message)
2407 {
2408 if (expected->message == actual->message &&
2409 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2410 {
2411 if (expected->flags & wparam)
2412 {
2413 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2414 {
2415 todo_wine {
2416 failcount ++;
2417 if (strcmp(winetest_platform, "wine")) dump++;
2418 ok_( file, line) (FALSE,
2419 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2420 context, count, expected->message, expected->wParam, actual->wParam);
2421 }
2422 }
2423 else
2424 {
2425 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2426 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2427 context, count, expected->message, expected->wParam, actual->wParam);
2428 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2429 }
2430
2431 }
2432 if (expected->flags & lparam)
2433 {
2434 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2435 {
2436 todo_wine {
2437 failcount ++;
2438 if (strcmp(winetest_platform, "wine")) dump++;
2439 ok_( file, line) (FALSE,
2440 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2441 context, count, expected->message, expected->lParam, actual->lParam);
2442 }
2443 }
2444 else
2445 {
2446 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2447 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2448 context, count, expected->message, expected->lParam, actual->lParam);
2449 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2450 }
2451 }
2452 if ((expected->flags & optional) &&
2453 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2454 {
2455 /* don't match optional messages if their defwinproc or parent status differs */
2456 expected++;
2457 count++;
2458 continue;
2459 }
2460 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2461 {
2462 todo_wine {
2463 failcount ++;
2464 if (strcmp(winetest_platform, "wine")) dump++;
2465 ok_( file, line) (FALSE,
2466 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2467 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2468 }
2469 }
2470 else
2471 {
2472 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2473 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2474 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2475 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2476 }
2477
2478 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2479 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2480 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2481 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2482
2483 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2484 "%s: %u: the msg 0x%04x should have been %s\n",
2485 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2486 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2487
2488 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2489 "%s: %u: the msg 0x%04x was expected in %s\n",
2490 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2491 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2492
2493 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2494 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2495 context, count, expected->message);
2496 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2497
2498 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2499 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2500 context, count, expected->message);
2501 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2502
2503 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2504 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2505 context, count, expected->message);
2506 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2507
2508 expected++;
2509 actual++;
2510 }
2511 /* silently drop hook messages if there is no support for them */
2512 else if ((expected->flags & optional) ||
2513 ((expected->flags & hook) && !hCBT_hook) ||
2514 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2515 ((expected->flags & kbd_hook) && !hKBD_hook))
2516 expected++;
2517 else if (todo)
2518 {
2519 failcount++;
2520 todo_wine {
2521 if (strcmp(winetest_platform, "wine")) dump++;
2522 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2523 context, count, expected->message, actual->message);
2524 }
2525 goto done;
2526 }
2527 else
2528 {
2529 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2530 context, count, expected->message, actual->message);
2531 dump++;
2532 expected++;
2533 actual++;
2534 }
2535 count++;
2536 }
2537
2538 /* skip all optional trailing messages */
2539 while (expected->message && ((expected->flags & optional) ||
2540 ((expected->flags & hook) && !hCBT_hook) ||
2541 ((expected->flags & winevent_hook) && !hEvent_hook)))
2542 expected++;
2543
2544 if (todo)
2545 {
2546 todo_wine {
2547 if (expected->message || actual->message) {
2548 failcount++;
2549 if (strcmp(winetest_platform, "wine")) dump++;
2550 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2551 context, count, expected->message, actual->message);
2552 }
2553 }
2554 }
2555 else
2556 {
2557 if (expected->message || actual->message)
2558 {
2559 dump++;
2560 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2561 context, count, expected->message, actual->message);
2562 }
2563 }
2564 if( todo && !failcount) /* succeeded yet marked todo */
2565 todo_wine {
2566 if (!strcmp(winetest_platform, "wine")) dump++;
2567 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2568 }
2569
2570 done:
2571 if (dump) dump_sequence(expected_list, context, file, line);
2572 flush_sequence();
2573 }
2574
2575 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2576
2577 /******************************** MDI test **********************************/
2578
2579 /* CreateWindow for MDI frame window, initially visible */
2580 static const struct message WmCreateMDIframeSeq[] = {
2581 { HCBT_CREATEWND, hook },
2582 { WM_GETMINMAXINFO, sent },
2583 { WM_NCCREATE, sent },
2584 { WM_NCCALCSIZE, sent|wparam, 0 },
2585 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2586 { WM_CREATE, sent },
2587 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2588 { WM_NOTIFYFORMAT, sent|optional },
2589 { WM_QUERYUISTATE, sent|optional },
2590 { WM_WINDOWPOSCHANGING, sent|optional },
2591 { WM_GETMINMAXINFO, sent|optional },
2592 { WM_NCCALCSIZE, sent|optional },
2593 { WM_WINDOWPOSCHANGED, sent|optional },
2594 { WM_SHOWWINDOW, sent|wparam, 1 },
2595 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2596 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2597 { HCBT_ACTIVATE, hook },
2598 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2599 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2600 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2601 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2602 { WM_NCACTIVATE, sent },
2603 { WM_GETTEXT, sent|defwinproc|optional },
2604 { WM_ACTIVATE, sent|wparam, 1 },
2605 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2606 { HCBT_SETFOCUS, hook },
2607 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2608 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2609 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2610 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2611 /* Win9x adds SWP_NOZORDER below */
2612 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2613 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2614 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2615 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2616 { WM_MOVE, sent },
2617 { 0 }
2618 };
2619 /* DestroyWindow for MDI frame window, initially visible */
2620 static const struct message WmDestroyMDIframeSeq[] = {
2621 { HCBT_DESTROYWND, hook },
2622 { 0x0090, sent|optional },
2623 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2624 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2625 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2626 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2627 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2628 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2629 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2630 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2631 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2632 { WM_DESTROY, sent },
2633 { WM_NCDESTROY, sent },
2634 { 0 }
2635 };
2636 /* CreateWindow for MDI client window, initially visible */
2637 static const struct message WmCreateMDIclientSeq[] = {
2638 { HCBT_CREATEWND, hook },
2639 { WM_NCCREATE, sent },
2640 { WM_NCCALCSIZE, sent|wparam, 0 },
2641 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2642 { WM_CREATE, sent },
2643 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2644 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2645 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2646 { WM_MOVE, sent },
2647 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2648 { WM_SHOWWINDOW, sent|wparam, 1 },
2649 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2650 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2651 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2652 { 0 }
2653 };
2654 /* ShowWindow(SW_SHOW) for MDI client window */
2655 static const struct message WmShowMDIclientSeq[] = {
2656 { WM_SHOWWINDOW, sent|wparam, 1 },
2657 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2658 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2659 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2660 { 0 }
2661 };
2662 /* ShowWindow(SW_HIDE) for MDI client window */
2663 static const struct message WmHideMDIclientSeq[] = {
2664 { WM_SHOWWINDOW, sent|wparam, 0 },
2665 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2666 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2667 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2668 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2669 { 0 }
2670 };
2671 /* DestroyWindow for MDI client window, initially visible */
2672 static const struct message WmDestroyMDIclientSeq[] = {
2673 { HCBT_DESTROYWND, hook },
2674 { 0x0090, sent|optional },
2675 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2676 { WM_SHOWWINDOW, sent|wparam, 0 },
2677 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2678 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2679 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2680 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2681 { WM_DESTROY, sent },
2682 { WM_NCDESTROY, sent },
2683 { 0 }
2684 };
2685 /* CreateWindow for MDI child window, initially visible */
2686 static const struct message WmCreateMDIchildVisibleSeq[] = {
2687 { HCBT_CREATEWND, hook },
2688 { WM_NCCREATE, sent },
2689 { WM_NCCALCSIZE, sent|wparam, 0 },
2690 { WM_CREATE, sent },
2691 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2692 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2693 { WM_MOVE, sent },
2694 /* Win2k sends wparam set to
2695 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2696 * while Win9x doesn't bother to set child window id according to
2697 * CLIENTCREATESTRUCT.idFirstChild
2698 */
2699 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2700 { WM_SHOWWINDOW, sent|wparam, 1 },
2701 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2702 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2703 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2704 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2705 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2706 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2707 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2708
2709 /* Win9x: message sequence terminates here. */
2710
2711 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2712 { HCBT_SETFOCUS, hook }, /* in MDI client */
2713 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2714 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2715 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2716 { WM_SETFOCUS, sent }, /* in MDI client */
2717 { HCBT_SETFOCUS, hook },
2718 { WM_KILLFOCUS, sent }, /* in MDI client */
2719 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2720 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2721 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2722 { WM_SETFOCUS, sent|defwinproc },
2723 { WM_MDIACTIVATE, sent|defwinproc },
2724 { 0 }
2725 };
2726 /* WM_CHILDACTIVATE sent to disabled window */
2727 static const struct message WmChildActivateDisabledWindowSeq[] = {
2728 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2729 { 0 }
2730 };
2731 /* WM_CHILDACTIVATE sent to enabled window */
2732 static const struct message WmChildActivateWindowSeq[] = {
2733 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2734 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2735 { WM_MDIACTIVATE, sent|defwinproc },
2736 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2737 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2738 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2739 { HCBT_SETFOCUS, hook },
2740 { WM_KILLFOCUS, sent|defwinproc },
2741 { WM_SETFOCUS, sent },
2742 { HCBT_SETFOCUS, hook },
2743 { WM_KILLFOCUS, sent },
2744 { WM_SETFOCUS, sent|defwinproc },
2745 { WM_MDIACTIVATE, sent|defwinproc },
2746 { 0 }
2747 };
2748 /* CreateWindow for MDI child window with invisible parent */
2749 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2750 { HCBT_CREATEWND, hook },
2751 { WM_GETMINMAXINFO, sent },
2752 { WM_NCCREATE, sent },
2753 { WM_NCCALCSIZE, sent|wparam, 0 },
2754 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2755 { WM_CREATE, sent },
2756 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2757 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2758 { WM_MOVE, sent },
2759 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2760 { WM_SHOWWINDOW, sent|wparam, 1 },
2761 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2762 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2763 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2764 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2765
2766 /* Win9x: message sequence terminates here. */
2767
2768 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2769 { HCBT_SETFOCUS, hook }, /* in MDI client */
2770 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2771 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2772 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2773 { WM_SETFOCUS, sent }, /* in MDI client */
2774 { HCBT_SETFOCUS, hook },
2775 { WM_KILLFOCUS, sent }, /* in MDI client */
2776 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2777 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2778 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2779 { WM_SETFOCUS, sent|defwinproc },
2780 { WM_MDIACTIVATE, sent|defwinproc },
2781 { 0 }
2782 };
2783 /* DestroyWindow for MDI child window, initially visible */
2784 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2785 { HCBT_DESTROYWND, hook },
2786 /* Win2k sends wparam set to
2787 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2788 * while Win9x doesn't bother to set child window id according to
2789 * CLIENTCREATESTRUCT.idFirstChild
2790 */
2791 { 0x0090, sent|optional },
2792 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2793 { WM_SHOWWINDOW, sent|wparam, 0 },
2794 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2795 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2796 { WM_ERASEBKGND, sent|parent|optional },
2797 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2798
2799 /* { WM_DESTROY, sent }
2800 * Win9x: message sequence terminates here.
2801 */
2802
2803 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2804 { WM_KILLFOCUS, sent },
2805 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2806 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2807 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2808 { WM_SETFOCUS, sent }, /* in MDI client */
2809
2810 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2811 { WM_KILLFOCUS, sent }, /* in MDI client */
2812 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2813 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2814 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2815 { WM_SETFOCUS, sent }, /* in MDI client */
2816
2817 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2818
2819 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2820 { WM_KILLFOCUS, sent },
2821 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2822 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2823 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2824 { WM_SETFOCUS, sent }, /* in MDI client */
2825
2826 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2827 { WM_KILLFOCUS, sent }, /* in MDI client */
2828 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2829 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2830 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2831 { WM_SETFOCUS, sent }, /* in MDI client */
2832
2833 { WM_DESTROY, sent },
2834
2835 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2836 { WM_KILLFOCUS, sent },
2837 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2838 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2839 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2840 { WM_SETFOCUS, sent }, /* in MDI client */
2841
2842 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2843 { WM_KILLFOCUS, sent }, /* in MDI client */
2844 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2845 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2846 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2847 { WM_SETFOCUS, sent }, /* in MDI client */
2848
2849 { WM_NCDESTROY, sent },
2850 { 0 }
2851 };
2852 /* CreateWindow for MDI child window, initially invisible */
2853 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2854 { HCBT_CREATEWND, hook },
2855 { WM_NCCREATE, sent },
2856 { WM_NCCALCSIZE, sent|wparam, 0 },
2857 { WM_CREATE, sent },
2858 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2859 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2860 { WM_MOVE, sent },
2861 /* Win2k sends wparam set to
2862 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2863 * while Win9x doesn't bother to set child window id according to
2864 * CLIENTCREATESTRUCT.idFirstChild
2865 */
2866 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2867 { 0 }
2868 };
2869 /* DestroyWindow for MDI child window, initially invisible */
2870 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2871 { HCBT_DESTROYWND, hook },
2872 /* Win2k sends wparam set to
2873 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2874 * while Win9x doesn't bother to set child window id according to
2875 * CLIENTCREATESTRUCT.idFirstChild
2876 */
2877 { 0x0090, sent|optional },
2878 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2879 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2880 { WM_DESTROY, sent },
2881 { WM_NCDESTROY, sent },
2882 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2883 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2884 { 0 }
2885 };
2886 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2887 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2888 { HCBT_CREATEWND, hook },
2889 { WM_NCCREATE, sent },
2890 { WM_NCCALCSIZE, sent|wparam, 0 },
2891 { WM_CREATE, sent },
2892 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2893 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2894 { WM_MOVE, sent },
2895 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2896 { WM_GETMINMAXINFO, sent },
2897 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2898 { WM_NCCALCSIZE, sent|wparam, 1 },
2899 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2900 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2901 /* in MDI frame */
2902 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2903 { WM_NCCALCSIZE, sent|wparam, 1 },
2904 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2905 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2906 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2907 /* Win2k sends wparam set to
2908 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2909 * while Win9x doesn't bother to set child window id according to
2910 * CLIENTCREATESTRUCT.idFirstChild
2911 */
2912 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2913 { WM_SHOWWINDOW, sent|wparam, 1 },
2914 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2915 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2916 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2917 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2918 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2919 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2920 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2921
2922 /* Win9x: message sequence terminates here. */
2923
2924 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2925 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2926 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2927 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2928 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2929 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2930 { HCBT_SETFOCUS, hook|optional },
2931 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2932 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2933 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2934 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2935 { WM_SETFOCUS, sent|defwinproc|optional },
2936 { WM_MDIACTIVATE, sent|defwinproc|optional },
2937 /* in MDI frame */
2938 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2939 { WM_NCCALCSIZE, sent|wparam, 1 },
2940 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2941 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2942 { 0 }
2943 };
2944 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2945 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2946 /* restore the 1st MDI child */
2947 { WM_SETREDRAW, sent|wparam, 0 },
2948 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2949 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2950 { WM_NCCALCSIZE, sent|wparam, 1 },
2951 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2952 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2953 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2954 /* in MDI frame */
2955 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2956 { WM_NCCALCSIZE, sent|wparam, 1 },
2957 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2958 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2959 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2960 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2961 /* create the 2nd MDI child */
2962 { HCBT_CREATEWND, hook },
2963 { WM_NCCREATE, sent },
2964 { WM_NCCALCSIZE, sent|wparam, 0 },
2965 { WM_CREATE, sent },
2966 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2967 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2968 { WM_MOVE, sent },
2969 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2970 { WM_GETMINMAXINFO, sent },
2971 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2972 { WM_NCCALCSIZE, sent|wparam, 1 },
2973 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2974 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2975 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2976 /* in MDI frame */
2977 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2978 { WM_NCCALCSIZE, sent|wparam, 1 },
2979 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2980 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2981 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2982 /* Win2k sends wparam set to
2983 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2984 * while Win9x doesn't bother to set child window id according to
2985 * CLIENTCREATESTRUCT.idFirstChild
2986 */
2987 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2988 { WM_SHOWWINDOW, sent|wparam, 1 },
2989 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2990 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2991 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2992 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2993 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2994 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2995
2996 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2997 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2998
2999 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3000
3001 /* Win9x: message sequence terminates here. */
3002
3003 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3004 { HCBT_SETFOCUS, hook },
3005 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3006 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3007 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3008 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3009 { WM_SETFOCUS, sent }, /* in MDI client */
3010 { HCBT_SETFOCUS, hook },
3011 { WM_KILLFOCUS, sent }, /* in MDI client */
3012 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3013 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3014 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3015 { WM_SETFOCUS, sent|defwinproc },
3016
3017 { WM_MDIACTIVATE, sent|defwinproc },
3018 /* in MDI frame */
3019 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3020 { WM_NCCALCSIZE, sent|wparam, 1 },
3021 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3022 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3023 { 0 }
3024 };
3025 /* WM_MDICREATE MDI child window, initially visible and maximized */
3026 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3027 { WM_MDICREATE, sent },
3028 { HCBT_CREATEWND, hook },
3029 { WM_NCCREATE, sent },
3030 { WM_NCCALCSIZE, sent|wparam, 0 },
3031 { WM_CREATE, sent },
3032 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3033 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3034 { WM_MOVE, sent },
3035 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3036 { WM_GETMINMAXINFO, sent },
3037 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3038 { WM_NCCALCSIZE, sent|wparam, 1 },
3039 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3040 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3041
3042 /* in MDI frame */
3043 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3044 { WM_NCCALCSIZE, sent|wparam, 1 },
3045 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3046 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3047 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3048
3049 /* Win2k sends wparam set to
3050 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3051 * while Win9x doesn't bother to set child window id according to
3052 * CLIENTCREATESTRUCT.idFirstChild
3053 */
3054 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3055 { WM_SHOWWINDOW, sent|wparam, 1 },
3056 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3057
3058 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3059
3060 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3061 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3062 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3063
3064 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3065 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3066
3067 /* Win9x: message sequence terminates here. */
3068
3069 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3070 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3071 { HCBT_SETFOCUS, hook }, /* in MDI client */
3072 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3073 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3074 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3075 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3076 { HCBT_SETFOCUS, hook|optional },
3077 { WM_KILLFOCUS, sent }, /* in MDI client */
3078 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3079 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3080 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3081 { WM_SETFOCUS, sent|defwinproc },
3082
3083 { WM_MDIACTIVATE, sent|defwinproc },
3084
3085 /* in MDI child */
3086 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3087 { WM_NCCALCSIZE, sent|wparam, 1 },
3088 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3089 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3090
3091 /* in MDI frame */
3092 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3093 { WM_NCCALCSIZE, sent|wparam, 1 },
3094 { 0x0093, sent|defwinproc|optional },
3095 { 0x0093, sent|defwinproc|optional },
3096 { 0x0093, sent|defwinproc|optional },
3097 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3098 { WM_MOVE, sent|defwinproc },
3099 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3100
3101 /* in MDI client */
3102 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3103 { WM_NCCALCSIZE, sent|wparam, 1 },
3104 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3105 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3106
3107 /* in MDI child */
3108 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3109 { WM_NCCALCSIZE, sent|wparam, 1 },
3110 { 0x0093, sent|optional },
3111 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3112 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3113
3114 { 0x0093, sent|optional },
3115 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3116 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3117 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3118 { 0x0093, sent|defwinproc|optional },
3119 { 0x0093, sent|defwinproc|optional },
3120 { 0x0093, sent|defwinproc|optional },
3121 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3122 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3123
3124 { 0 }
3125 };
3126 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3127 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3128 { HCBT_CREATEWND, hook },
3129 { WM_GETMINMAXINFO, sent },
3130 { WM_NCCREATE, sent },
3131 { WM_NCCALCSIZE, sent|wparam, 0 },
3132 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3133 { WM_CREATE, sent },
3134 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3135 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3136 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3137 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3138 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3139 { WM_MOVE, sent },
3140 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3141 { WM_GETMINMAXINFO, sent },
3142 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3143 { WM_GETMINMAXINFO, sent|defwinproc },
3144 { WM_NCCALCSIZE, sent|wparam, 1 },
3145 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3146 { WM_MOVE, sent|defwinproc },
3147 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3148 /* in MDI frame */
3149 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3150 { WM_NCCALCSIZE, sent|wparam, 1 },
3151 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3152 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3153 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3154 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3155 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3156 /* Win2k sends wparam set to
3157 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3158 * while Win9x doesn't bother to set child window id according to
3159 * CLIENTCREATESTRUCT.idFirstChild
3160 */
3161 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3162 { 0 }
3163 };
3164 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3165 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3166 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3167 { HCBT_SYSCOMMAND, hook },
3168 { WM_CLOSE, sent|defwinproc },
3169 { WM_MDIDESTROY, sent }, /* in MDI client */
3170
3171 /* bring the 1st MDI child to top */
3172 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3173 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3174
3175 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3176
3177 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3178 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3179 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3180
3181 /* maximize the 1st MDI child */
3182 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3183 { WM_GETMINMAXINFO, sent|defwinproc },
3184 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3185 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3186 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3187 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3188 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3189
3190 /* restore the 2nd MDI child */
3191 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3192 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3193 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3194 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3195
3196 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3197
3198 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3199 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3200
3201 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3202
3203 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3204 /* in MDI frame */
3205 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3206 { WM_NCCALCSIZE, sent|wparam, 1 },
3207 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3208 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3209 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3210
3211 /* bring the 1st MDI child to top */
3212 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3213 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3214 { HCBT_SETFOCUS, hook },
3215 { WM_KILLFOCUS, sent|defwinproc },
3216 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3217 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3218 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3219 { WM_SETFOCUS, sent }, /* in MDI client */
3220 { HCBT_SETFOCUS, hook },
3221 { WM_KILLFOCUS, sent }, /* in MDI client */
3222 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3223 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3224 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3225 { WM_SETFOCUS, sent|defwinproc },
3226 { WM_MDIACTIVATE, sent|defwinproc },
3227 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3228
3229 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3230 { WM_SHOWWINDOW, sent|wparam, 1 },
3231 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3232 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3233 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3234 { WM_MDIREFRESHMENU, sent },
3235
3236 { HCBT_DESTROYWND, hook },
3237 /* Win2k sends wparam set to
3238 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3239 * while Win9x doesn't bother to set child window id according to
3240 * CLIENTCREATESTRUCT.idFirstChild
3241 */
3242 { 0x0090, sent|defwinproc|optional },
3243 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3244 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3245 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3246 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3247 { WM_ERASEBKGND, sent|parent|optional },
3248 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3249
3250 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3251 { WM_DESTROY, sent|defwinproc },
3252 { WM_NCDESTROY, sent|defwinproc },
3253 { 0 }
3254 };
3255 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3256 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3257 { WM_MDIDESTROY, sent }, /* in MDI client */
3258 { WM_SHOWWINDOW, sent|wparam, 0 },
3259 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3260 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3261 { WM_ERASEBKGND, sent|parent|optional },
3262 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3263
3264 { HCBT_SETFOCUS, hook },
3265 { WM_KILLFOCUS, sent },
3266 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3267 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3268 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3269 { WM_SETFOCUS, sent }, /* in MDI client */
3270 { HCBT_SETFOCUS, hook },
3271 { WM_KILLFOCUS, sent }, /* in MDI client */
3272 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3273 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3274 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3275 { WM_SETFOCUS, sent },
3276
3277 /* in MDI child */
3278 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3279 { WM_NCCALCSIZE, sent|wparam, 1 },
3280 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3281 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3282
3283 /* in MDI frame */
3284 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3285 { WM_NCCALCSIZE, sent|wparam, 1 },
3286 { 0x0093, sent|defwinproc|optional },
3287 { 0x0093, sent|defwinproc|optional },
3288 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3289 { WM_MOVE, sent|defwinproc },
3290 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3291
3292 /* in MDI client */
3293 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3294 { WM_NCCALCSIZE, sent|wparam, 1 },
3295 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3296 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3297
3298 /* in MDI child */
3299 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3300 { WM_NCCALCSIZE, sent|wparam, 1 },
3301 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3302 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3303
3304 /* in MDI child */
3305 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3306 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3307 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3308 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3309
3310 /* in MDI frame */
3311 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3312 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3313 { 0x0093, sent|defwinproc|optional },
3314 { 0x0093, sent|defwinproc|optional },
3315 { 0x0093, sent|defwinproc|optional },
3316 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3317 { WM_MOVE, sent|defwinproc },
3318 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3319
3320 /* in MDI client */
3321 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3322 { WM_NCCALCSIZE, sent|wparam, 1 },
3323 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3324 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3325
3326 /* in MDI child */
3327 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3328 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3329 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3330 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3331 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3332 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3333
3334 { 0x0093, sent|defwinproc|optional },
3335 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3336 { 0x0093, sent|defwinproc|optional },
3337 { 0x0093, sent|defwinproc|optional },
3338 { 0x0093, sent|defwinproc|optional },
3339 { 0x0093, sent|optional },
3340
3341 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3342 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3343 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3344 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3345 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3346
3347 /* in MDI frame */
3348 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3349 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3350 { 0x0093, sent|defwinproc|optional },
3351 { 0x0093, sent|defwinproc|optional },
3352 { 0x0093, sent|defwinproc|optional },
3353 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3354 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3355 { 0x0093, sent|optional },
3356
3357 { WM_NCACTIVATE, sent|wparam, 0 },
3358 { WM_MDIACTIVATE, sent },
3359
3360 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3361 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3362 { WM_NCCALCSIZE, sent|wparam, 1 },
3363
3364 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3365
3366 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3367 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3368 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3369
3370 /* in MDI child */
3371 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3372 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3373 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3374 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3375
3376 /* in MDI frame */
3377 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3378 { WM_NCCALCSIZE, sent|wparam, 1 },
3379 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3380 { WM_MOVE, sent|defwinproc },
3381 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3382
3383 /* in MDI client */
3384 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3385 { WM_NCCALCSIZE, sent|wparam, 1 },
3386 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3387 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3388 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3389 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3390 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3391 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3392 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3393
3394 { HCBT_SETFOCUS, hook },
3395 { WM_KILLFOCUS, sent },
3396 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3397 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3398 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3399 { WM_SETFOCUS, sent }, /* in MDI client */
3400
3401 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3402
3403 { HCBT_DESTROYWND, hook },
3404 /* Win2k sends wparam set to
3405 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3406 * while Win9x doesn't bother to set child window id according to
3407 * CLIENTCREATESTRUCT.idFirstChild
3408 */
3409 { 0x0090, sent|optional },
3410 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3411
3412 { WM_SHOWWINDOW, sent|wparam, 0 },
3413 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3414 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3415 { WM_ERASEBKGND, sent|parent|optional },
3416 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3417
3418 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3419 { WM_DESTROY, sent },
3420 { WM_NCDESTROY, sent },
3421 { 0 }
3422 };
3423 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3424 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3425 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3426 { WM_GETMINMAXINFO, sent },
3427 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3428 { WM_NCCALCSIZE, sent|wparam, 1 },
3429 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3430 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3431
3432 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3433 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3434 { HCBT_SETFOCUS, hook|optional },
3435 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3436 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3437 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3438 { HCBT_SETFOCUS, hook|optional },
3439 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3440 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3441 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3442 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3443 { WM_SETFOCUS, sent|optional|defwinproc },
3444 { WM_MDIACTIVATE, sent|optional|defwinproc },
3445 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3446 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3447 /* in MDI frame */
3448 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3449 { WM_NCCALCSIZE, sent|wparam, 1 },
3450 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3451 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3452 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3453 { 0 }
3454 };
3455 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3456 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3457 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3458 { WM_GETMINMAXINFO, sent },
3459 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3460 { WM_GETMINMAXINFO, sent|defwinproc },
3461 { WM_NCCALCSIZE, sent|wparam, 1 },
3462 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3463 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3464
3465 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3466 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3467 { HCBT_SETFOCUS, hook|optional },
3468 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3469 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3470 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3471 { HCBT_SETFOCUS, hook|optional },
3472 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3473 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3474 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3475 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3476 { WM_SETFOCUS, sent|defwinproc|optional },
3477 { WM_MDIACTIVATE, sent|defwinproc|optional },
3478 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3479 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3480 { WM_SIZE, sent|defwinproc|optional },
3481 { 0 }
3482 };
3483 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3484 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3485 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3486 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3487 { WM_GETMINMAXINFO, sent },
3488 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3489 { WM_GETMINMAXINFO, sent|defwinproc },
3490 { WM_NCCALCSIZE, sent|wparam, 1 },
3491 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3492 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3493 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3494 { WM_MOVE, sent|defwinproc },
3495 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3496
3497 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3498 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3499 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3500 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3501 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3502 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3503 /* in MDI frame */
3504 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3505 { WM_NCCALCSIZE, sent|wparam, 1 },
3506 { 0x0093, sent|defwinproc|optional },
3507 { 0x0094, sent|defwinproc|optional },
3508 { 0x0094, sent|defwinproc|optional },
3509 { 0x0094, sent|defwinproc|optional },
3510 { 0x0094, sent|defwinproc|optional },
3511 { 0x0093, sent|defwinproc|optional },
3512 { 0x0093, sent|defwinproc|optional },
3513 { 0x0091, sent|defwinproc|optional },
3514 { 0x0092, sent|defwinproc|optional },
3515 { 0x0092, sent|defwinproc|optional },
3516 { 0x0092, sent|defwinproc|optional },
3517 { 0x0092, sent|defwinproc|optional },
3518 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3519 { WM_MOVE, sent|defwinproc },
3520 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3521 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3522 /* in MDI client */
3523 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3524 { WM_NCCALCSIZE, sent|wparam, 1 },
3525 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3526 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3527 /* in MDI child */
3528 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3529 { WM_GETMINMAXINFO, sent|defwinproc },
3530 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3531 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3532 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3533 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3534 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3535 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3536 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3537 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3538 /* in MDI frame */
3539 { 0x0093, sent|optional },
3540 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3541 { 0x0093, sent|defwinproc|optional },
3542 { 0x0093, sent|defwinproc|optional },
3543 { 0x0093, sent|defwinproc|optional },
3544 { 0x0091, sent|defwinproc|optional },
3545 { 0x0092, sent|defwinproc|optional },
3546 { 0x0092, sent|defwinproc|optional },
3547 { 0x0092, sent|defwinproc|optional },
3548 { 0x0092, sent|defwinproc|optional },
3549 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3550 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3551 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3552 { 0 }
3553 };
3554 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3555 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3556 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3557 { WM_GETMINMAXINFO, sent },
3558 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3559 { WM_NCCALCSIZE, sent|wparam, 1 },
3560 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3561 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3562 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3563 /* in MDI frame */
3564 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3565 { WM_NCCALCSIZE, sent|wparam, 1 },
3566 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3567 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3568 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3569 { 0 }
3570 };
3571 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3572 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3573 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3574 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3575 { WM_NCCALCSIZE, sent|wparam, 1 },
3576 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3577 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3578 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3579 /* in MDI frame */
3580 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3581 { WM_NCCALCSIZE, sent|wparam, 1 },
3582 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3583 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3584 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3585 { 0 }
3586 };
3587 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3588 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3589 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3590 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3591 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3592 { WM_NCCALCSIZE, sent|wparam, 1 },
3593 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3594 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3595 { WM_MOVE, sent|defwinproc },
3596 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3597 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3598 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3599 { HCBT_SETFOCUS, hook },
3600 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3601 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3602 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3603 { WM_SETFOCUS, sent },
3604 { 0 }
3605 };
3606 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3607 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3608 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3609 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3610 { WM_NCCALCSIZE, sent|wparam, 1 },
3611 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3612 { WM_MOVE, sent|defwinproc },
3613 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3614 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3615 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3616 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3617 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3618 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3619 { 0 }
3620 };
3621 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3622 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3623 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3624 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3625 { WM_NCCALCSIZE, sent|wparam, 1 },
3626 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3627 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3628 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3629 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3630 /* in MDI frame */
3631 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3632 { WM_NCCALCSIZE, sent|wparam, 1 },
3633 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3634 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3635 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3636 { 0 }
3637 };
3638
3639 static HWND mdi_client;
3640 static WNDPROC old_mdi_client_proc;
3641
3642 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3643 {
3644 struct recvd_message msg;
3645
3646 /* do not log painting messages */
3647 if (message != WM_PAINT &&
3648 message != WM_NCPAINT &&
3649 message != WM_SYNCPAINT &&
3650 message != WM_ERASEBKGND &&
3651 message != WM_NCHITTEST &&
3652 message != WM_GETTEXT &&
3653 message != WM_MDIGETACTIVE &&
3654 !ignore_message( message ))
3655 {
3656 msg.hwnd = hwnd;
3657 msg.message = message;
3658 msg.flags = sent|wparam|lparam;
3659 msg.wParam = wParam;
3660 msg.lParam = lParam;
3661 msg.descr = "mdi client";
3662 add_message(&msg);
3663 }
3664
3665 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3666 }
3667
3668 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3669 {
3670 static LONG defwndproc_counter = 0;
3671 LRESULT ret;
3672 struct recvd_message msg;
3673
3674 /* do not log painting messages */
3675 if (message != WM_PAINT &&
3676 message != WM_NCPAINT &&
3677 message != WM_SYNCPAINT &&
3678 message != WM_ERASEBKGND &&
3679 message != WM_NCHITTEST &&
3680 message != WM_GETTEXT &&
3681 !ignore_message( message ))
3682 {
3683 switch (message)
3684 {
3685 case WM_MDIACTIVATE:
3686 {
3687 HWND active, client = GetParent(hwnd);
3688
3689 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3690
3691 if (hwnd == (HWND)lParam) /* if we are being activated */
3692 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3693 else
3694 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3695 break;
3696 }
3697 }
3698
3699 msg.hwnd = hwnd;
3700 msg.message = message;
3701 msg.flags = sent|wparam|lparam;
3702 if (defwndproc_counter) msg.flags |= defwinproc;
3703 msg.wParam = wParam;
3704 msg.lParam = lParam;
3705 msg.descr = "mdi child";
3706 add_message(&msg);
3707 }
3708
3709 defwndproc_counter++;
3710 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3711 defwndproc_counter--;
3712
3713 return ret;
3714 }
3715
3716 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3717 {
3718 static LONG defwndproc_counter = 0;
3719 LRESULT ret;
3720 struct recvd_message msg;
3721
3722 /* do not log painting messages */
3723 if (message != WM_PAINT &&
3724 message != WM_NCPAINT &&
3725 message != WM_SYNCPAINT &&
3726 message != WM_ERASEBKGND &&
3727 message != WM_NCHITTEST &&
3728 message != WM_GETTEXT &&
3729 !ignore_message( message ))
3730 {
3731 msg.hwnd = hwnd;
3732 msg.message = message;
3733 msg.flags = sent|wparam|lparam;
3734 if (defwndproc_counter) msg.flags |= defwinproc;
3735 msg.wParam = wParam;
3736 msg.lParam = lParam;
3737 msg.descr = "mdi frame";
3738 add_message(&msg);
3739 }
3740
3741 defwndproc_counter++;
3742 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3743 defwndproc_counter--;
3744
3745 return ret;
3746 }
3747
3748 static BOOL mdi_RegisterWindowClasses(void)
3749 {
3750 WNDCLASSA cls;
3751
3752 cls.style = 0;
3753 cls.lpfnWndProc = mdi_frame_wnd_proc;
3754 cls.cbClsExtra = 0;
3755 cls.cbWndExtra = 0;
3756 cls.hInstance = GetModuleHandleA(0);
3757 cls.hIcon = 0;
3758 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3759 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3760 cls.lpszMenuName = NULL;
3761 cls.lpszClassName = "MDI_frame_class";
3762 if (!RegisterClassA(&cls)) return FALSE;
3763
3764 cls.lpfnWndProc = mdi_child_wnd_proc;
3765 cls.lpszClassName = "MDI_child_class";
3766 if (!RegisterClassA(&cls)) return FALSE;
3767
3768 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3769 old_mdi_client_proc = cls.lpfnWndProc;
3770 cls.hInstance = GetModuleHandleA(0);
3771 cls.lpfnWndProc = mdi_client_hook_proc;
3772 cls.lpszClassName = "MDI_client_class";
3773 if (!RegisterClassA(&cls)) assert(0);
3774
3775 return TRUE;
3776 }
3777
3778 static void test_mdi_messages(void)
3779 {
3780 MDICREATESTRUCTA mdi_cs;
3781 CLIENTCREATESTRUCT client_cs;
3782 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3783 BOOL zoomed;
3784 RECT rc;
3785 HMENU hMenu = CreateMenu();
3786 LONG val;
3787
3788 if (!mdi_RegisterWindowClasses()) assert(0);
3789
3790 flush_sequence();
3791
3792 trace("creating MDI frame window\n");
3793 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3794 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3795 WS_MAXIMIZEBOX | WS_VISIBLE,
3796 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3797 GetDesktopWindow(), hMenu,
3798 GetModuleHandleA(0), NULL);
3799 assert(mdi_frame);
3800 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3801
3802 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3803 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3804
3805 trace("creating MDI client window\n");
3806 GetClientRect(mdi_frame, &rc);
3807 client_cs.hWindowMenu = 0;
3808 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3809 mdi_client = CreateWindowExA(0, "MDI_client_class",
3810 NULL,
3811 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3812 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3813 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3814 assert(mdi_client);
3815 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3816
3817 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3818 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3819 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3820
3821 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3822 ok(!active_child, "wrong active MDI child %p\n", active_child);
3823 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3824
3825 SetFocus(0);
3826 flush_sequence();
3827
3828 trace("creating invisible MDI child window\n");
3829 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3830 WS_CHILD,
3831 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3832 mdi_client, 0, GetModuleHandleA(0), NULL);
3833 assert(mdi_child);
3834
3835 flush_sequence();
3836 ShowWindow(mdi_child, SW_SHOWNORMAL);
3837 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3838
3839 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3840 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3841
3842 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3843 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3844
3845 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3846 ok(!active_child, "wrong active MDI child %p\n", active_child);
3847 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3848
3849 ShowWindow(mdi_child, SW_HIDE);
3850 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3851 flush_sequence();
3852
3853 ShowWindow(mdi_child, SW_SHOW);
3854 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3855
3856 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3857 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3858
3859 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3860 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3861
3862 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3863 ok(!active_child, "wrong active MDI child %p\n", active_child);
3864 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3865
3866 DestroyWindow(mdi_child);
3867 flush_sequence();
3868
3869 trace("creating visible MDI child window\n");
3870 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3871 WS_CHILD | WS_VISIBLE,
3872 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3873 mdi_client, 0, GetModuleHandleA(0), NULL);
3874 assert(mdi_child);
3875 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3876
3877 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3878 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3879
3880 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3881 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3882
3883 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3884 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3885 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3886 flush_sequence();
3887
3888 DestroyWindow(mdi_child);
3889 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3890
3891 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3892 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3893
3894 /* Win2k: MDI client still returns a just destroyed child as active
3895 * Win9x: MDI client returns 0
3896 */
3897 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3898 ok(active_child == mdi_child || /* win2k */
3899 !active_child, /* win9x */
3900 "wrong active MDI child %p\n", active_child);
3901 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3902
3903 flush_sequence();
3904
3905 trace("creating invisible MDI child window\n");
3906 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3907 WS_CHILD,
3908 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3909 mdi_client, 0, GetModuleHandleA(0), NULL);
3910 assert(mdi_child2);
3911 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3912
3913 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3914 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3915
3916 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3917 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3918
3919 /* Win2k: MDI client still returns a just destroyed child as active
3920 * Win9x: MDI client returns mdi_child2
3921 */
3922 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3923 ok(active_child == mdi_child || /* win2k */
3924 active_child == mdi_child2, /* win9x */
3925 "wrong active MDI child %p\n", active_child);
3926 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3927 flush_sequence();
3928
3929 ShowWindow(mdi_child2, SW_MAXIMIZE);
3930 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3931
3932 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3933 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3934
3935 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3936 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3937 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3938 flush_sequence();
3939
3940 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3941 ok(GetFocus() == mdi_child2 || /* win2k */
3942 GetFocus() == 0, /* win9x */
3943 "wrong focus window %p\n", GetFocus());
3944
3945 SetFocus(0);
3946 flush_sequence();
3947
3948 ShowWindow(mdi_child2, SW_HIDE);
3949 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3950
3951 ShowWindow(mdi_child2, SW_RESTORE);
3952 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3953 flush_sequence();
3954
3955 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3956 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3957
3958 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3959 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3960 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3961 flush_sequence();
3962
3963 SetFocus(0);
3964 flush_sequence();
3965
3966 ShowWindow(mdi_child2, SW_HIDE);
3967 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3968
3969 ShowWindow(mdi_child2, SW_SHOW);
3970 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3971
3972 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3973 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3974
3975 ShowWindow(mdi_child2, SW_MAXIMIZE);
3976 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3977
3978 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3979 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3980
3981 ShowWindow(mdi_child2, SW_RESTORE);
3982 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3983
3984 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3985 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3986
3987 ShowWindow(mdi_child2, SW_MINIMIZE);
3988 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE);
3989
3990 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3991 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3992
3993 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3994 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3995 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3996 flush_sequence();
3997
3998 ShowWindow(mdi_child2, SW_RESTORE);
3999 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4000
4001 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4002 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4003
4004 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4005 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4006 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4007 flush_sequence();
4008
4009 SetFocus(0);
4010 flush_sequence();
4011
4012 ShowWindow(mdi_child2, SW_HIDE);
4013 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4014
4015 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4016 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4017
4018 DestroyWindow(mdi_child2);
4019 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4020
4021 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4022 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4023
4024 trace("Testing WM_CHILDACTIVATE\n");
4025
4026 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4027 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4028 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4029 mdi_client, 0, GetModuleHandleA(0), NULL);
4030
4031 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4032 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4033 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4034 mdi_client, 0, GetModuleHandleA(0), NULL);
4035
4036 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4037 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4038 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4039
4040 flush_sequence();
4041 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4042 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4043
4044 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4045 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4046 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4047 flush_sequence();
4048
4049 EnableWindow(mdi_child, TRUE);
4050
4051 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4052 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4053 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4054
4055 flush_sequence();
4056 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4057 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4058
4059 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4060 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4061 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4062 flush_sequence();
4063
4064 DestroyWindow(mdi_child);
4065 DestroyWindow(mdi_child2);
4066 flush_sequence();
4067
4068 /* test for maximized MDI children */
4069 trace("creating maximized visible MDI child window 1\n");
4070 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4071 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4072 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4073 mdi_client, 0, GetModuleHandleA(0), NULL);
4074 assert(mdi_child);
4075 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4076 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4077
4078 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4079 ok(GetFocus() == mdi_child || /* win2k */
4080 GetFocus() == 0, /* win9x */
4081 "wrong focus window %p\n", GetFocus());
4082
4083 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4084 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4085 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4086 flush_sequence();
4087
4088 trace("creating maximized visible MDI child window 2\n");
4089 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4090 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4091 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4092 mdi_client, 0, GetModuleHandleA(0), NULL);
4093 assert(mdi_child2);
4094 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4095 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4096 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4097
4098 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4099 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4100
4101 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4102 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4103 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4104 flush_sequence();
4105
4106 trace("destroying maximized visible MDI child window 2\n");
4107 DestroyWindow(mdi_child2);
4108 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4109
4110 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4111
4112 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4113 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4114
4115 /* Win2k: MDI client still returns a just destroyed child as active
4116 * Win9x: MDI client returns 0
4117 */
4118 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4119 ok(active_child == mdi_child2 || /* win2k */
4120 !active_child, /* win9x */
4121 "wrong active MDI child %p\n", active_child);
4122 flush_sequence();
4123
4124 ShowWindow(mdi_child, SW_MAXIMIZE);
4125 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4126 flush_sequence();
4127
4128 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4129 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4130
4131 trace("re-creating maximized visible MDI child window 2\n");
4132 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4133 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4134 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4135 mdi_client, 0, GetModuleHandleA(0), NULL);
4136 assert(mdi_child2);
4137 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4138 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4139 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4140
4141 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4142 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4143
4144 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4145 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4146 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4147 flush_sequence();
4148
4149 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4150 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4151 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4152
4153 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4154 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4155 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4156
4157 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4158 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4159 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4160 flush_sequence();
4161
4162 DestroyWindow(mdi_child);
4163 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4164
4165 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4166 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4167
4168 /* Win2k: MDI client still returns a just destroyed child as active
4169 * Win9x: MDI client returns 0
4170 */
4171 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4172 ok(active_child == mdi_child || /* win2k */
4173 !active_child, /* win9x */
4174 "wrong active MDI child %p\n", active_child);
4175 flush_sequence();
4176
4177 trace("creating maximized invisible MDI child window\n");
4178 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4179 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4180 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4181 mdi_client, 0, GetModuleHandleA(0), NULL);
4182 assert(mdi_child2);
4183 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4184 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4185 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4186 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4187
4188 /* Win2k: MDI client still returns a just destroyed child as active
4189 * Win9x: MDI client returns 0
4190 */
4191 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4192 ok(active_child == mdi_child || /* win2k */
4193 !active_child || active_child == mdi_child2, /* win9x */
4194 "wrong active MDI child %p\n", active_child);
4195 flush_sequence();
4196
4197 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4198 ShowWindow(mdi_child2, SW_MAXIMIZE);
4199 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4200 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4201 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4202 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4203
4204 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4205 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4206 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4207 flush_sequence();
4208
4209 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4210 flush_sequence();
4211
4212 /* end of test for maximized MDI children */
4213 SetFocus(0);
4214 flush_sequence();
4215 trace("creating maximized visible MDI child window 1(Switch test)\n");
4216 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4217 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4218 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4219 mdi_client, 0, GetModuleHandleA(0), NULL);
4220 assert(mdi_child);
4221 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4222 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4223
4224 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4225 ok(GetFocus() == mdi_child || /* win2k */
4226 GetFocus() == 0, /* win9x */
4227 "wrong focus window %p(Switch test)\n", GetFocus());
4228
4229 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4230 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4231 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4232 flush_sequence();
4233
4234 trace("creating maximized visible MDI child window 2(Switch test)\n");
4235 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4236 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4237 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4238 mdi_client, 0, GetModuleHandleA(0), NULL);
4239 assert(mdi_child2);
4240 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4241
4242 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4243 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4244
4245 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4246 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4247
4248 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4249 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4250 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4251 flush_sequence();
4252
4253 trace("Switch child window.\n");
4254 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4255 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4256 trace("end of test for switch maximized MDI children\n");
4257 flush_sequence();
4258
4259 /* Prepare for switching test of not maximized MDI children */
4260 ShowWindow( mdi_child, SW_NORMAL );
4261 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4262 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4263 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4264 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4265 flush_sequence();
4266
4267 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4268 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4269 trace("end of test for switch not maximized MDI children\n");
4270 flush_sequence();
4271
4272 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4273 flush_sequence();
4274
4275 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4276 flush_sequence();
4277
4278 SetFocus(0);
4279 flush_sequence();
4280 /* end of tests for switch maximized/not maximized MDI children */
4281
4282 mdi_cs.szClass = "MDI_child_Class";
4283 mdi_cs.szTitle = "MDI child";
4284 mdi_cs.hOwner = GetModuleHandleA(0);
4285 mdi_cs.x = 0;
4286 mdi_cs.y = 0;
4287 mdi_cs.cx = CW_USEDEFAULT;
4288 mdi_cs.cy = CW_USEDEFAULT;
4289 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4290 mdi_cs.lParam = 0;
4291 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4292 ok(mdi_child != 0, "MDI child creation failed\n");
4293 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4294
4295 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4296
4297 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4298 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4299
4300 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4301 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4302 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4303
4304 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4305 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4306 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4307 flush_sequence();
4308
4309 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4310 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4311
4312 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4313 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4314 ok(!active_child, "wrong active MDI child %p\n", active_child);
4315
4316 SetFocus(0);
4317 flush_sequence();
4318
4319 val = GetWindowLongA(mdi_client, 0);
4320 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4321 DestroyWindow(mdi_client);
4322 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4323
4324 /* test maximization of MDI child with invisible parent */
4325 client_cs.hWindowMenu = 0;
4326 mdi_client = CreateWindowA("MDI_client_class",
4327 NULL,
4328 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4329 0, 0, 660, 430,
4330 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4331 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4332
4333 ShowWindow(mdi_client, SW_HIDE);
4334 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4335
4336 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4337 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4338 0, 0, 650, 440,
4339 mdi_client, 0, GetModuleHandleA(0), NULL);
4340 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4341
4342 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4343 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4344 zoomed = IsZoomed(mdi_child);
4345 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4346
4347 ShowWindow(mdi_client, SW_SHOW);
4348 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4349
4350 DestroyWindow(mdi_child);
4351 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4352
4353 /* end of test for maximization of MDI child with invisible parent */
4354
4355 DestroyWindow(mdi_client);
4356 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4357
4358 DestroyWindow(mdi_frame);
4359 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4360 }
4361 /************************* End of MDI test **********************************/
4362
4363 static void test_WM_SETREDRAW(HWND hwnd)
4364 {
4365 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4366
4367 flush_events();
4368 flush_sequence();
4369
4370 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4371 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4372
4373 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4374 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4375
4376 flush_sequence();
4377 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4378 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4379
4380 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4381 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4382
4383 /* restore original WS_VISIBLE state */
4384 SetWindowLongA(hwnd, GWL_STYLE, style);
4385
4386 flush_events();
4387 flush_sequence();
4388 }
4389
4390 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4391 {
4392 struct recvd_message msg;
4393
4394 if (ignore_message( message )) return 0;
4395
4396 switch (message)
4397 {
4398 /* ignore */
4399 case WM_MOUSEMOVE:
4400 case WM_NCMOUSEMOVE:
4401 case WM_NCMOUSELEAVE:
4402 case WM_SETCURSOR:
4403 return 0;
4404 case WM_NCHITTEST:
4405 return HTCLIENT;
4406 }
4407
4408 msg.hwnd = hwnd;
4409 msg.message = message;
4410 msg.flags = sent|wparam|lparam;
4411 msg.wParam = wParam;
4412 msg.lParam = lParam;
4413 msg.descr = "dialog";
4414 add_message(&msg);
4415
4416 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4417 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4418 return 0;
4419 }
4420
4421 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4422 {
4423 struct recvd_message msg;
4424
4425 if (ignore_message( message )) return 0;
4426
4427 switch (message)
4428 {
4429 /* ignore */
4430 case WM_MOUSEMOVE:
4431 case WM_NCMOUSEMOVE:
4432 case WM_NCMOUSELEAVE:
4433 case WM_SETCURSOR:
4434 return 0;
4435 case WM_NCHITTEST:
4436 return HTCLIENT;
4437 }
4438
4439 msg.hwnd = hwnd;
4440 msg.message = message;
4441 msg.flags = sent|wparam|lparam;
4442 msg.wParam = wParam;
4443 msg.lParam = lParam;
4444 msg.descr = "dialog";
4445 add_message(&msg);
4446
4447 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4448 return 0;
4449 }
4450
4451 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4452 {
4453 DWORD style, exstyle;
4454 INT xmin, xmax;
4455 BOOL ret;
4456
4457 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4458 style = GetWindowLongA(hwnd, GWL_STYLE);
4459 /* do not be confused by WS_DLGFRAME set */
4460 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4461
4462 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4463 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4464
4465 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4466 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4467 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4468 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4469 else
4470 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4471
4472 style = GetWindowLongA(hwnd, GWL_STYLE);
4473 if (set) ok(style & set, "style %08x should be set\n", set);
4474 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4475
4476 /* a subsequent call should do nothing */
4477 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4478 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4479 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4480
4481 xmin = 0xdeadbeef;
4482 xmax = 0xdeadbeef;
4483 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4484 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4485 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4486 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4487 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4488 }
4489
4490 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4491 {
4492 DWORD style, exstyle;
4493 SCROLLINFO si;
4494 BOOL ret;
4495
4496 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4497 style = GetWindowLongA(hwnd, GWL_STYLE);
4498 /* do not be confused by WS_DLGFRAME set */
4499 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4500
4501 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4502 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4503
4504 si.cbSize = sizeof(si);
4505 si.fMask = SIF_RANGE;
4506 si.nMin = min;
4507 si.nMax = max;
4508 SetScrollInfo(hwnd, ctl, &si, TRUE);
4509 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4510 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4511 else
4512 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4513
4514 style = GetWindowLongA(hwnd, GWL_STYLE);
4515 if (set) ok(style & set, "style %08x should be set\n", set);
4516 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4517
4518 /* a subsequent call should do nothing */
4519 SetScrollInfo(hwnd, ctl, &si, TRUE);
4520 if (style & WS_HSCROLL)
4521 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4522 else if (style & WS_VSCROLL)
4523 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4524 else
4525 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4526
4527 si.fMask = SIF_PAGE;
4528 si.nPage = 5;
4529 SetScrollInfo(hwnd, ctl, &si, FALSE);
4530 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4531
4532 si.fMask = SIF_POS;
4533 si.nPos = max - 1;
4534 SetScrollInfo(hwnd, ctl, &si, FALSE);
4535 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4536
4537 si.fMask = SIF_RANGE;
4538 si.nMin = 0xdeadbeef;
4539 si.nMax = 0xdeadbeef;
4540 ret = GetScrollInfo(hwnd, ctl, &si);
4541 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4542 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4543 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4544 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4545 }
4546
4547 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4548 static void test_scroll_messages(HWND hwnd)
4549 {
4550 SCROLLINFO si;
4551 INT min, max;
4552 BOOL ret;
4553
4554 flush_events();
4555 flush_sequence();
4556
4557 min = 0xdeadbeef;
4558 max = 0xdeadbeef;
4559 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4560 ok( ret, "GetScrollRange error %d\n", GetLastError());
4561 if (sequence->message != WmGetScrollRangeSeq[0].message)
4562 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4563 /* values of min and max are undefined */
4564 flush_sequence();
4565
4566 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4567 ok( ret, "SetScrollRange error %d\n", GetLastError());
4568 if (sequence->message != WmSetScrollRangeSeq[0].message)
4569 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4570 flush_sequence();
4571
4572 min = 0xdeadbeef;
4573 max = 0xdeadbeef;
4574 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4575 ok( ret, "GetScrollRange error %d\n", GetLastError());
4576 if (sequence->message != WmGetScrollRangeSeq[0].message)
4577 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4578 /* values of min and max are undefined */
4579 flush_sequence();
4580
4581 si.cbSize = sizeof(si);
4582 si.fMask = SIF_RANGE;
4583 si.nMin = 20;
4584 si.nMax = 160;
4585 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4586 if (sequence->message != WmSetScrollRangeSeq[0].message)
4587 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4588 flush_sequence();
4589
4590 si.fMask = SIF_PAGE;
4591 si.nPage = 10;
4592 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4593 if (sequence->message != WmSetScrollRangeSeq[0].message)
4594 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4595 flush_sequence();
4596
4597 si.fMask = SIF_POS;
4598 si.nPos = 20;
4599 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4600 if (sequence->message != WmSetScrollRangeSeq[0].message)
4601 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4602 flush_sequence();
4603
4604 si.fMask = SIF_RANGE;
4605 si.nMin = 0xdeadbeef;
4606 si.nMax = 0xdeadbeef;
4607 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4608 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4609 if (sequence->message != WmGetScrollInfoSeq[0].message)
4610 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4611 /* values of min and max are undefined */
4612 flush_sequence();
4613
4614 /* set WS_HSCROLL */
4615 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4616 /* clear WS_HSCROLL */
4617 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4618
4619 /* set WS_HSCROLL */
4620 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4621 /* clear WS_HSCROLL */
4622 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4623
4624 /* set WS_VSCROLL */
4625 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4626 /* clear WS_VSCROLL */
4627 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4628
4629 /* set WS_VSCROLL */
4630 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4631 /* clear WS_VSCROLL */
4632 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4633 }
4634
4635 static void test_showwindow(void)
4636 {
4637 HWND hwnd, hchild;
4638 RECT rc;
4639
4640 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4641 100, 100, 200, 200, 0, 0, 0, NULL);
4642 ok (hwnd != 0, "Failed to create overlapped window\n");
4643 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4644 0, 0, 10, 10, hwnd, 0, 0, NULL);
4645 ok (hchild != 0, "Failed to create child\n");
4646 flush_sequence();
4647
4648 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4649 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4650 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4651 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4652
4653 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4654 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4655 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4656 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4657 /* back to invisible */
4658 ShowWindow(hchild, SW_HIDE);
4659 ShowWindow(hwnd, SW_HIDE);
4660 flush_sequence();
4661 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4662 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4663 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4664 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4665 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4666 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4667 flush_sequence();
4668 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4669 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4670 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4671 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4672 ShowWindow( hwnd, SW_SHOW);
4673 flush_sequence();
4674 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4675 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4676 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4677
4678 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4679 ShowWindow( hchild, SW_HIDE);
4680 flush_sequence();
4681 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4682 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4683 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4684
4685 SetCapture(hchild);
4686 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4687 DestroyWindow(hchild);
4688 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4689
4690 DestroyWindow(hwnd);
4691 flush_sequence();
4692
4693 /* Popup windows */
4694 /* Test 1:
4695 * 1. Create invisible maximized popup window.
4696 * 2. Move and resize it.
4697 * 3. Show it maximized.
4698 */
4699 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4700 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4701 100, 100, 200, 200, 0, 0, 0, NULL);
4702 ok (hwnd != 0, "Failed to create popup window\n");
4703 ok(IsZoomed(hwnd), "window should be maximized\n");
4704 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4705
4706 GetWindowRect(hwnd, &rc);
4707 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4708 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4709 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4710 /* Reset window's size & position */
4711 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4712 ok(IsZoomed(hwnd), "window should be maximized\n");
4713 flush_sequence();
4714
4715 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4716 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4717 ok(IsZoomed(hwnd), "window should be maximized\n");
4718 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4719
4720 GetWindowRect(hwnd, &rc);
4721 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4722 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4723 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4724 DestroyWindow(hwnd);
4725 flush_sequence();
4726
4727 /* Test 2:
4728 * 1. Create invisible maximized popup window.
4729 * 2. Show it maximized.
4730 */
4731 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4732 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4733 100, 100, 200, 200, 0, 0, 0, NULL);
4734 ok (hwnd != 0, "Failed to create popup window\n");
4735 ok(IsZoomed(hwnd), "window should be maximized\n");
4736 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4737
4738 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4739 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4740 ok(IsZoomed(hwnd), "window should be maximized\n");
4741 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4742 DestroyWindow(hwnd);
4743 flush_sequence();
4744
4745 /* Test 3:
4746 * 1. Create visible maximized popup window.
4747 */
4748 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4749 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4750 100, 100, 200, 200, 0, 0, 0, NULL);
4751 ok (hwnd != 0, "Failed to create popup window\n");
4752 ok(IsZoomed(hwnd), "window should be maximized\n");
4753 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4754 DestroyWindow(hwnd);
4755 flush_sequence();
4756
4757 /* Test 4:
4758 * 1. Create visible popup window.
4759 * 2. Maximize it.
4760 */
4761 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4762 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4763 100, 100, 200, 200, 0, 0, 0, NULL);
4764 ok (hwnd != 0, "Failed to create popup window\n");
4765 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4766 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4767
4768 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4769 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4770 ok(IsZoomed(hwnd), "window should be maximized\n");
4771 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4772 DestroyWindow(hwnd);
4773 flush_sequence();
4774 }
4775
4776 static void test_recursive_activation(void)
4777 {
4778 static const struct message seq[] =
4779 {
4780 { HCBT_ACTIVATE, hook },
4781 { WM_NCACTIVATE, sent|wparam, TRUE },
4782 { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
4783 { HCBT_ACTIVATE, hook },
4784 { WM_NCACTIVATE, sent|wparam, FALSE },
4785 { WM_ACTIVATE, sent|wparam, WA_INACTIVE },
4786 { WM_SETFOCUS, sent|optional },
4787 { 0 }
4788 };
4789 HWND hwnd, recursive;
4790
4791 hwnd = CreateWindowExA(0, "SimpleWindowClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
4792 100, 100, 200, 200, 0, 0, 0, NULL);
4793 ok(hwnd != 0, "Failed to create simple window\n");
4794
4795 recursive = CreateWindowExA(0, "RecursiveActivationClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
4796 10, 10, 50, 50, hwnd, 0, 0, NULL);
4797 ok(recursive != 0, "Failed to create recursive activation window\n");
4798 SetActiveWindow(hwnd);
4799
4800 flush_sequence();
4801 SetActiveWindow(recursive);
4802 ok_sequence(seq, "Recursive Activation", FALSE);
4803
4804 DestroyWindow(recursive);
4805 DestroyWindow(hwnd);
4806 flush_sequence();
4807 }
4808
4809 static void test_sys_menu(void)
4810 {
4811 HWND hwnd;
4812 HMENU hmenu;
4813 UINT state;
4814
4815 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4816 100, 100, 200, 200, 0, 0, 0, NULL);
4817 ok (hwnd != 0, "Failed to create overlapped window\n");
4818
4819 flush_sequence();
4820
4821 /* test existing window without CS_NOCLOSE style */
4822 hmenu = GetSystemMenu(hwnd, FALSE);
4823 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4824
4825 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4826 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4827 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4828
4829 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4830 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4831
4832 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4833 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4834 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4835
4836 EnableMenuItem(hmenu, SC_CLOSE, 0);
4837 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4838
4839 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4840 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4841 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4842
4843 /* test whether removing WS_SYSMENU destroys a system menu */
4844 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4845 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4846 flush_sequence();
4847 hmenu = GetSystemMenu(hwnd, FALSE);
4848 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4849
4850 DestroyWindow(hwnd);
4851
4852 /* test new window with CS_NOCLOSE style */
4853 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4854 100, 100, 200, 200, 0, 0, 0, NULL);
4855 ok (hwnd != 0, "Failed to create overlapped window\n");
4856
4857 hmenu = GetSystemMenu(hwnd, FALSE);
4858 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4859
4860 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4861 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4862
4863 DestroyWindow(hwnd);
4864
4865 /* test new window without WS_SYSMENU style */
4866 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4867 100, 100, 200, 200, 0, 0, 0, NULL);
4868 ok(hwnd != 0, "Failed to create overlapped window\n");
4869
4870 hmenu = GetSystemMenu(hwnd, FALSE);
4871 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4872
4873 DestroyWindow(hwnd);
4874 }
4875
4876 /* For shown WS_OVERLAPPEDWINDOW */
4877 static const struct message WmSetIcon_1[] = {
4878 { WM_SETICON, sent },
4879 { 0x00AE, sent|defwinproc|optional }, /* XP */
4880 { WM_GETTEXT, sent|defwinproc|optional },
4881 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4882 { 0 }
4883 };
4884
4885 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4886 static const struct message WmSetIcon_2[] = {
4887 { WM_SETICON, sent },
4888 { 0 }
4889 };
4890
4891 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4892 static const struct message WmInitEndSession[] = {
4893 { 0x003B, sent },
4894 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4895 { 0 }
4896 };
4897
4898 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4899 static const struct message WmInitEndSession_2[] = {
4900 { 0x003B, sent },
4901 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4902 { 0 }
4903 };
4904
4905 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4906 static const struct message WmInitEndSession_3[] = {
4907 { 0x003B, sent },
4908 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4909 { 0 }
4910 };
4911
4912 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4913 static const struct message WmInitEndSession_4[] = {
4914 { 0x003B, sent },
4915 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4916 { 0 }
4917 };
4918
4919 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4920 static const struct message WmInitEndSession_5[] = {
4921 { 0x003B, sent },
4922 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4923 { 0 }
4924 };
4925
4926 static const struct message WmOptionalPaint[] = {
4927 { WM_PAINT, sent|optional },
4928 { WM_NCPAINT, sent|beginpaint|optional },
4929 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4930 { WM_ERASEBKGND, sent|beginpaint|optional },
4931 { 0 }
4932 };
4933
4934 static const struct message WmZOrder[] = {
4935 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4936 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4937 { HCBT_ACTIVATE, hook },
4938 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4939 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4940 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4941 { WM_GETTEXT, sent|optional },
4942 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4943 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4944 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4945 { WM_GETTEXT, sent|defwinproc|optional },
4946 { WM_GETTEXT, sent|defwinproc|optional },
4947 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4948 { HCBT_SETFOCUS, hook },
4949 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4950 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4951 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4952 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4953 { WM_GETTEXT, sent|optional },
4954 { WM_NCCALCSIZE, sent|optional },
4955 { 0 }
4956 };
4957
4958 static void CALLBACK apc_test_proc(ULONG_PTR param)
4959 {
4960 /* nothing */
4961 }
4962
4963 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4964 {
4965 DWORD ret;
4966 MSG msg;
4967
4968 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4969 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4970
4971 PostMessageA(hwnd, WM_USER, 0, 0);
4972
4973 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4974 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4975
4976 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4977 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4978
4979 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4980 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4981
4982 PostMessageA(hwnd, WM_USER, 0, 0);
4983
4984 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4985 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4986
4987 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4988 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4989
4990 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4991 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4992 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4993
4994 PostMessageA(hwnd, WM_USER, 0, 0);
4995
4996 /* new incoming message causes it to become signaled again */
4997 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4998 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4999
5000 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5001 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5002 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5003 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5004
5005 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5006 PostMessageA( hwnd, WM_USER, 0, 0 );
5007 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5008 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5009
5010 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5011 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5012
5013 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5014 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5015
5016 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5017 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5018 ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5019
5020 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5021 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5022
5023 /* but even with MWMO_ALERTABLE window events are preferred */
5024 PostMessageA( hwnd, WM_USER, 0, 0 );
5025
5026 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5027 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5028
5029 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5030 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5031
5032 /* the APC call is still queued */
5033 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5034 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5035 }
5036
5037 static void test_WM_DEVICECHANGE(HWND hwnd)
5038 {
5039 DWORD ret;
5040 MSG msg;
5041 int i;
5042 static const WPARAM wparams[] = {0,
5043 DBT_DEVNODES_CHANGED,
5044 DBT_QUERYCHANGECONFIG,
5045 DBT_CONFIGCHANGED,
5046 DBT_CONFIGCHANGECANCELED,
5047 DBT_NO_DISK_SPACE,
5048 DBT_LOW_DISK_SPACE,
5049 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5050 DBT_DEVICEARRIVAL, /* 0x8000 */
5051 DBT_DEVICEQUERYREMOVE,
5052 DBT_DEVICEQUERYREMOVEFAILED,
5053 DBT_DEVICEREMOVEPENDING,
5054 DBT_DEVICEREMOVECOMPLETE,
5055 DBT_DEVICETYPESPECIFIC,
5056 DBT_CUSTOMEVENT};
5057
5058 for (i = 0; i < ARRAY_SIZE(wparams); i++)
5059 {
5060 SetLastError(0xdeadbeef);
5061 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5062 if (wparams[i] & 0x8000)
5063 {
5064 ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5065 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5066 }
5067 else
5068 {
5069 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5070 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5071 memset(&msg, 0, sizeof(msg));
5072 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5073 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5074 }
5075 }
5076 }
5077
5078 static DWORD CALLBACK show_window_thread(LPVOID arg)
5079 {
5080 HWND hwnd = arg;
5081
5082 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5083 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5084
5085 return 0;
5086 }
5087
5088 /* Helper function to easier test SetWindowPos messages */
5089 #define test_msg_setpos( expected_list, flags, todo ) \
5090 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5091 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5092 {
5093 HWND hwnd;
5094
5095 flush_events();
5096 flush_sequence();
5097 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5098 10, 10, 100, 100, NULL, 0, 0, NULL );
5099 ok (hwnd != 0, "Failed to create popup window\n");
5100 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5101 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5102 DestroyWindow(hwnd);
5103 }
5104
5105 /* test if we receive the right sequence of messages */
5106 static void test_messages(void)
5107 {
5108 DWORD tid;
5109 HANDLE hthread;
5110 HWND hwnd, hparent, hchild;
5111 HWND hchild2, hbutton;
5112 HMENU hmenu;
5113 MSG msg;
5114 LRESULT res;
5115 POINT pos;
5116 BOOL ret;
5117
5118 flush_sequence();
5119
5120 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5121 100, 100, 200, 200, 0, 0, 0, NULL);
5122 ok (hwnd != 0, "Failed to create overlapped window\n");
5123 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5124
5125 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5126 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5127 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5128
5129 /* test WM_SETREDRAW on a not visible top level window */
5130 test_WM_SETREDRAW(hwnd);
5131
5132 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5133 flush_events();
5134 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5135 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5136
5137 ok(GetActiveWindow() == hwnd, "window should be active\n");
5138 ok(GetFocus() == hwnd, "window should have input focus\n");
5139 ShowWindow(hwnd, SW_HIDE);
5140 flush_events();
5141 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5142
5143 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5144 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5145 flush_events();
5146 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5147
5148 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5149 hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5150 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5151 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5152 CloseHandle(hthread);
5153 flush_events();
5154 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5155
5156 ShowWindow(hwnd, SW_SHOW);
5157 flush_events();
5158 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5159
5160 ShowWindow(hwnd, SW_HIDE);
5161 flush_events();
5162 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5163
5164 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5165 flush_events();
5166 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5167 flush_sequence();
5168
5169 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5170 {
5171 ShowWindow(hwnd, SW_RESTORE);
5172 flush_events();
5173 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5174 flush_sequence();
5175 }
5176
5177 ShowWindow(hwnd, SW_MINIMIZE);
5178 flush_events();
5179 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE);
5180 flush_sequence();
5181
5182 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5183 {
5184 ShowWindow(hwnd, SW_RESTORE);
5185 flush_events();
5186 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5187 flush_sequence();
5188 }
5189
5190 ShowWindow(hwnd, SW_SHOW);
5191 flush_events();
5192 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5193
5194 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5195 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5196 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5197 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5198
5199 /* test WM_SETREDRAW on a visible top level window */
5200 ShowWindow(hwnd, SW_SHOW);
5201 flush_events();
5202 test_WM_SETREDRAW(hwnd);
5203
5204 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5205 test_scroll_messages(hwnd);
5206
5207 /* test resizing and moving */
5208 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5209 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5210 flush_events();
5211 flush_sequence();
5212 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5213 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5214 flush_events();
5215 flush_sequence();
5216 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5217 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5218 flush_events();
5219 flush_sequence();
5220
5221 /* popups don't get WM_GETMINMAXINFO */
5222 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5223 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5224 flush_sequence();
5225 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5226 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5227
5228 DestroyWindow(hwnd);
5229 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5230
5231 /* Test if windows are correctly drawn when first shown */
5232
5233 /* Visible, redraw */
5234 flush_events();
5235 flush_sequence();
5236 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5237 10, 10, 100, 100, NULL, 0, 0, NULL );
5238 ok (hwnd != 0, "Failed to create popup window\n");
5239 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5240 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5241 DestroyWindow(hwnd);
5242
5243 /* Invisible, show, message */
5244 flush_events();
5245 flush_sequence();
5246 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5247 10, 10, 100, 100, NULL, 0, 0, NULL );
5248 ok (hwnd != 0, "Failed to create popup window\n");
5249 ShowWindow(hwnd, SW_SHOW);
5250 SendMessageW(hwnd, WM_PAINT, 0, 0);
5251 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5252 DestroyWindow(hwnd);
5253
5254 /* Invisible, show maximized, redraw */
5255 flush_events();
5256 flush_sequence();
5257 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5258 10, 10, 100, 100, NULL, 0, 0, NULL );
5259 ok (hwnd != 0, "Failed to create popup window\n");
5260 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5261 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5262 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5263 DestroyWindow(hwnd);
5264
5265 /* Test SetWindowPos */
5266 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5267 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5268 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5269 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5270
5271 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5272 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5273 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5274 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5275 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5276
5277 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5278 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5279 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5280 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5281 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5282 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5283
5284 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5285 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5286 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5287 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5288 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5289 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5290
5291 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5292 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5293 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5294 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5295 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5296 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5297
5298 /* Test SetWindowPos with child windows */
5299 flush_events();
5300 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5301 100, 100, 200, 200, 0, 0, 0, NULL);
5302 ok (hparent != 0, "Failed to create parent window\n");
5303
5304 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5305 0, 0, 10, 10, hparent, 0, 0, NULL);
5306 ok (hchild != 0, "Failed to create child window\n");
5307 flush_sequence();
5308 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5309 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5310 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5311 DestroyWindow(hchild);
5312 DestroyWindow(hparent);
5313
5314 flush_events();
5315 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5316 100, 100, 200, 200, 0, 0, 0, NULL);
5317 ok (hparent != 0, "Failed to create parent window\n");
5318
5319 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5320 0, 0, 10, 10, hparent, 0, 0, NULL);
5321 ok (hchild != 0, "Failed to create child window\n");
5322 flush_sequence();
5323 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5324 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5325 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5326 DestroyWindow(hchild);
5327 DestroyWindow(hparent);
5328
5329 /* Test message sequence for extreme position and size */
5330
5331 flush_sequence();
5332 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5333 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5334 ok (hwnd != 0, "Failed to create popup window\n");
5335 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE);
5336 DestroyWindow(hwnd);
5337
5338
5339 /* Test child windows */
5340
5341 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5342 100, 100, 200, 200, 0, 0, 0, NULL);
5343 ok (hparent != 0, "Failed to create parent window\n");
5344 flush_sequence();
5345
5346 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5347 0, 0, 10, 10, hparent, 0, 0, NULL);
5348 ok (hchild != 0, "Failed to create child window\n");
5349 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5350 DestroyWindow(hchild);
5351 flush_sequence();
5352
5353 /* visible child window with a caption */
5354 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5355 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5356 0, 0, 10, 10, hparent, 0, 0, NULL);
5357 ok (hchild != 0, "Failed to create child window\n");
5358 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5359
5360 trace("testing scroll APIs on a visible child window %p\n", hchild);
5361 test_scroll_messages(hchild);
5362
5363 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5364 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5365
5366 DestroyWindow(hchild);
5367 flush_sequence();
5368
5369 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5370 0, 0, 10, 10, hparent, 0, 0, NULL);
5371 ok (hchild != 0, "Failed to create child window\n");
5372 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5373
5374 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5375 100, 100, 50, 50, hparent, 0, 0, NULL);
5376 ok (hchild2 != 0, "Failed to create child2 window\n");
5377 flush_sequence();
5378
5379 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5380 0, 100, 50, 50, hchild, 0, 0, NULL);
5381 ok (hbutton != 0, "Failed to create button window\n");
5382
5383 /* test WM_SETREDRAW on a not visible child window */
5384 test_WM_SETREDRAW(hchild);
5385
5386 ShowWindow(hchild, SW_SHOW);
5387 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5388
5389 /* check parent messages too */
5390 log_all_parent_messages++;
5391 ShowWindow(hchild, SW_HIDE);
5392 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5393 log_all_parent_messages--;
5394
5395 ShowWindow(hchild, SW_SHOW);
5396 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5397
5398 ShowWindow(hchild, SW_HIDE);
5399 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5400
5401 ShowWindow(hchild, SW_SHOW);
5402 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5403
5404 /* test WM_SETREDRAW on a visible child window */
5405 test_WM_SETREDRAW(hchild);
5406
5407 log_all_parent_messages++;
5408 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5409 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5410 log_all_parent_messages--;
5411
5412 ShowWindow(hchild, SW_HIDE);
5413 flush_sequence();
5414 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5415 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5416
5417 ShowWindow(hchild, SW_HIDE);
5418 flush_sequence();
5419 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5420 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5421
5422 /* DestroyWindow sequence below expects that a child has focus */
5423 SetFocus(hchild);
5424 flush_sequence();
5425
5426 DestroyWindow(hchild);
5427 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5428 DestroyWindow(hchild2);
5429 DestroyWindow(hbutton);
5430
5431 flush_sequence();
5432 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5433 0, 0, 100, 100, hparent, 0, 0, NULL);
5434 ok (hchild != 0, "Failed to create child popup window\n");
5435 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5436 DestroyWindow(hchild);
5437
5438 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5439 flush_sequence();
5440 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5441 0, 0, 100, 100, hparent, 0, 0, NULL);
5442 ok (hchild != 0, "Failed to create popup window\n");
5443 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5444 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5445 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5446 flush_sequence();
5447 ShowWindow(hchild, SW_SHOW);
5448 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5449 flush_sequence();
5450 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5451 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5452 flush_sequence();
5453 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5454 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5455 DestroyWindow(hchild);
5456
5457 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5458 * changes nothing in message sequences.
5459 */
5460 flush_sequence();
5461 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5462 0, 0, 100, 100, hparent, 0, 0, NULL);
5463 ok (hchild != 0, "Failed to create popup window\n");
5464 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5465 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5466 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5467 flush_sequence();
5468 ShowWindow(hchild, SW_SHOW);
5469 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5470 flush_sequence();
5471 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5472 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5473 DestroyWindow(hchild);
5474
5475 flush_sequence();
5476 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5477 0, 0, 100, 100, hparent, 0, 0, NULL);
5478 ok(hwnd != 0, "Failed to create custom dialog window\n");
5479 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5480
5481 if(0) {
5482 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5483 test_scroll_messages(hwnd);
5484 }
5485
5486 flush_sequence();
5487
5488 test_def_id = TRUE;
5489 SendMessageA(hwnd, WM_NULL, 0, 0);
5490
5491 flush_sequence();
5492 after_end_dialog = TRUE;
5493 EndDialog( hwnd, 0 );
5494 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5495
5496 DestroyWindow(hwnd);
5497 after_end_dialog = FALSE;
5498 test_def_id = FALSE;
5499
5500 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5501 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5502
5503 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5504 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5505 ok(hwnd != 0, "Failed to create custom dialog window\n");
5506 flush_sequence();
5507 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5508 ShowWindow(hwnd, SW_SHOW);
5509 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5510
5511 flush_events();
5512 flush_sequence();
5513 ret = DrawMenuBar(hwnd);
5514 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5515 flush_events();
5516 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5517 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5518
5519 DestroyWindow(hwnd);
5520
5521 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5522 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5523 ok(hwnd != 0, "Failed to create custom dialog window\n");
5524 flush_events();
5525 flush_sequence();
5526 ret = DrawMenuBar(hwnd);
5527 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5528 flush_events();
5529 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5530
5531 DestroyWindow(hwnd);
5532
5533 flush_sequence();
5534 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5535 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5536
5537 DestroyWindow(hparent);
5538 flush_sequence();
5539
5540 /* Message sequence for SetMenu */
5541 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5542 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5543 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5544
5545 hmenu = CreateMenu();
5546 ok (hmenu != 0, "Failed to create menu\n");
5547 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5548 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5549 100, 100, 200, 200, 0, hmenu, 0, NULL);
5550 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5551 ok (SetMenu(hwnd, 0), "SetMenu\n");
5552 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5553 ok (SetMenu(hwnd, 0), "SetMenu\n");
5554 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5555 ShowWindow(hwnd, SW_SHOW);
5556 UpdateWindow( hwnd );
5557 flush_events();
5558 flush_sequence();
5559 ok (SetMenu(hwnd, 0), "SetMenu\n");
5560 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5561 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5562 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5563
5564 UpdateWindow( hwnd );
5565 flush_events();
5566 flush_sequence();
5567 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5568 flush_events();
5569 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5570
5571 DestroyWindow(hwnd);
5572 flush_sequence();
5573
5574 /* Message sequence for EnableWindow */
5575 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5576 100, 100, 200, 200, 0, 0, 0, NULL);
5577 ok (hparent != 0, "Failed to create parent window\n");
5578 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5579 0, 0, 10, 10, hparent, 0, 0, NULL);
5580 ok (hchild != 0, "Failed to create child window\n");
5581
5582 SetFocus(hchild);
5583 flush_events();
5584 flush_sequence();
5585
5586 EnableWindow(hparent, FALSE);
5587 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5588
5589 EnableWindow(hparent, FALSE);
5590 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5591
5592 EnableWindow(hparent, TRUE);
5593 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5594
5595 EnableWindow(hparent, TRUE);
5596 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5597
5598 flush_events();
5599 flush_sequence();
5600
5601 test_MsgWaitForMultipleObjects(hparent);
5602 test_WM_DEVICECHANGE(hparent);
5603
5604 /* the following test causes an exception in user.exe under win9x */
5605 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5606 {
5607 DestroyWindow(hparent);
5608 flush_sequence();
5609 return;
5610 }
5611 PostMessageW( hparent, WM_USER+1, 0, 0 );
5612 /* PeekMessage(NULL) fails, but still removes the message */
5613 SetLastError(0xdeadbeef);
5614 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5615 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5616 GetLastError() == 0xdeadbeef, /* NT4 */
5617 "last error is %d\n", GetLastError() );
5618 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5619 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5620
5621 DestroyWindow(hchild);
5622 DestroyWindow(hparent);
5623 flush_sequence();
5624
5625 /* Message sequences for WM_SETICON */
5626 trace("testing WM_SETICON\n");
5627 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5628 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5629 NULL, NULL, 0);
5630 ShowWindow(hwnd, SW_SHOW);
5631 UpdateWindow(hwnd);
5632 flush_events();
5633 flush_sequence();
5634 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5635 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5636
5637 ShowWindow(hwnd, SW_HIDE);
5638 flush_events();
5639 flush_sequence();
5640 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5641 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5642 DestroyWindow(hwnd);
5643 flush_sequence();
5644
5645 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5646 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5647 NULL, NULL, 0);
5648 ShowWindow(hwnd, SW_SHOW);
5649 UpdateWindow(hwnd);
5650 flush_events();
5651 flush_sequence();
5652 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5653 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5654
5655 ShowWindow(hwnd, SW_HIDE);
5656 flush_events();
5657 flush_sequence();
5658 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5659 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5660
5661 flush_sequence();
5662 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5663 if (!res)
5664 {
5665 todo_wine win_skip( "Message 0x3b not supported\n" );
5666 goto done;
5667 }
5668 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5669 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5670 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5671 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5672 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5673 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5674 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5675 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5676
5677 flush_sequence();
5678 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5679 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5680 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5681 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5682 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5683 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5684
5685 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5686 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5687 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5688
5689 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5690 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5691 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5692
5693 done:
5694 DestroyWindow(hwnd);
5695 flush_sequence();
5696 }
5697
5698 static void test_setwindowpos(void)
5699 {
5700 HWND hwnd;
5701 RECT rc;
5702 LRESULT res;
5703 const INT winX = 100;
5704 const INT winY = 100;
5705 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5706
5707 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5708 0, 0, winX, winY, 0,
5709 NULL, NULL, 0);
5710
5711 GetWindowRect(hwnd, &rc);
5712 expect(sysX, rc.right);
5713 expect(winY, rc.bottom);
5714
5715 flush_events();
5716 flush_sequence();
5717 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5718 ok_sequence(WmZOrder, "Z-Order", TRUE);
5719 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5720
5721 GetWindowRect(hwnd, &rc);
5722 expect(sysX, rc.right);
5723 expect(winY, rc.bottom);
5724 DestroyWindow(hwnd);
5725 }
5726
5727 static void invisible_parent_tests(void)
5728 {
5729 HWND hparent, hchild;
5730
5731 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5732 100, 100, 200, 200, 0, 0, 0, NULL);
5733 ok (hparent != 0, "Failed to create parent window\n");
5734 flush_sequence();
5735
5736 /* test showing child with hidden parent */
5737
5738 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5739 0, 0, 10, 10, hparent, 0, 0, NULL);
5740 ok (hchild != 0, "Failed to create child window\n");
5741 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5742
5743 ShowWindow( hchild, SW_MINIMIZE );
5744 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5745 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5746 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5747
5748 /* repeat */
5749 flush_events();
5750 flush_sequence();
5751 ShowWindow( hchild, SW_MINIMIZE );
5752 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5753
5754 DestroyWindow(hchild);
5755 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5756 0, 0, 10, 10, hparent, 0, 0, NULL);
5757 flush_sequence();
5758
5759 ShowWindow( hchild, SW_MAXIMIZE );
5760 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5761 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5762 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5763
5764 /* repeat */
5765 flush_events();
5766 flush_sequence();
5767 ShowWindow( hchild, SW_MAXIMIZE );
5768 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5769
5770 DestroyWindow(hchild);
5771 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5772 0, 0, 10, 10, hparent, 0, 0, NULL);
5773 flush_sequence();
5774
5775 ShowWindow( hchild, SW_RESTORE );
5776 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5777 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5778 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5779
5780 DestroyWindow(hchild);
5781 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5782 0, 0, 10, 10, hparent, 0, 0, NULL);
5783 flush_sequence();
5784
5785 ShowWindow( hchild, SW_SHOWMINIMIZED );
5786 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5787 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5788 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5789
5790 /* repeat */
5791 flush_events();
5792 flush_sequence();
5793 ShowWindow( hchild, SW_SHOWMINIMIZED );
5794 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5795
5796 DestroyWindow(hchild);
5797 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5798 0, 0, 10, 10, hparent, 0, 0, NULL);
5799 flush_sequence();
5800
5801 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5802 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5803 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5804 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5805 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5806
5807 DestroyWindow(hchild);
5808 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5809 0, 0, 10, 10, hparent, 0, 0, NULL);
5810 flush_sequence();
5811
5812 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5813 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5814 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5815 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5816
5817 /* repeat */
5818 flush_events();
5819 flush_sequence();
5820 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5821 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5822
5823 DestroyWindow(hchild);
5824 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5825 0, 0, 10, 10, hparent, 0, 0, NULL);
5826 flush_sequence();
5827
5828 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5829 ShowWindow( hchild, SW_FORCEMINIMIZE );
5830 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5831 todo_wine {
5832 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5833 }
5834 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5835
5836 DestroyWindow(hchild);
5837 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5838 0, 0, 10, 10, hparent, 0, 0, NULL);
5839 flush_sequence();
5840
5841 ShowWindow( hchild, SW_SHOWNA );
5842 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5843 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5844 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5845
5846 /* repeat */
5847 flush_events();
5848 flush_sequence();
5849 ShowWindow( hchild, SW_SHOWNA );
5850 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5851
5852 DestroyWindow(hchild);
5853 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5854 0, 0, 10, 10, hparent, 0, 0, NULL);
5855 flush_sequence();
5856
5857 ShowWindow( hchild, SW_SHOW );
5858 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5859 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5860 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5861
5862 /* repeat */
5863 flush_events();
5864 flush_sequence();
5865 ShowWindow( hchild, SW_SHOW );
5866 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5867
5868 ShowWindow( hchild, SW_HIDE );
5869 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5870 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5871 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5872
5873 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5874 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5875 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5876 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5877
5878 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5879 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5880 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5881 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5882
5883 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5884 flush_sequence();
5885 DestroyWindow(hchild);
5886 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5887
5888 DestroyWindow(hparent);
5889 flush_sequence();
5890 }
5891
5892 /****************** button message test *************************/
5893 #define ID_BUTTON 0x000e
5894
5895 static const struct message WmSetFocusButtonSeq[] =
5896 {
5897 { HCBT_SETFOCUS, hook },
5898 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5899 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5900 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5901 { WM_SETFOCUS, sent|wparam, 0 },
5902 { WM_CTLCOLORBTN, sent|parent },
5903 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5904 { WM_APP, sent|wparam|lparam, 0, 0 },
5905 { 0 }
5906 };
5907 static const struct message WmKillFocusButtonSeq[] =
5908 {
5909 { HCBT_SETFOCUS, hook },
5910 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5911 { WM_KILLFOCUS, sent|wparam, 0 },
5912 { WM_CTLCOLORBTN, sent|parent },
5913 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5914 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5915 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5916 { WM_APP, sent|wparam|lparam, 0, 0 },
5917 { WM_PAINT, sent },
5918 { WM_CTLCOLORBTN, sent|parent },
5919 { 0 }
5920 };
5921 static const struct message WmSetFocusStaticSeq[] =
5922 {
5923 { HCBT_SETFOCUS, hook },
5924 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5925 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5926 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5927 { WM_SETFOCUS, sent|wparam, 0 },
5928 { WM_CTLCOLORSTATIC, sent|parent },
5929 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5930 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5931 { WM_APP, sent|wparam|lparam, 0, 0 },
5932 { 0 }
5933 };
5934 static const struct message WmKillFocusStaticSeq[] =
5935 {
5936 { HCBT_SETFOCUS, hook },
5937 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5938 { WM_KILLFOCUS, sent|wparam, 0 },
5939 { WM_CTLCOLORSTATIC, sent|parent },
5940 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5941 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5942 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5943 { WM_APP, sent|wparam|lparam, 0, 0 },
5944 { WM_PAINT, sent },
5945 { WM_CTLCOLORSTATIC, sent|parent },
5946 { 0 }
5947 };
5948 static const struct message WmSetFocusOwnerdrawSeq[] =
5949 {
5950 { HCBT_SETFOCUS, hook },
5951 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5952 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5953 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5954 { WM_SETFOCUS, sent|wparam, 0 },
5955 { WM_CTLCOLORBTN, sent|parent },
5956 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5957 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5958 { WM_APP, sent|wparam|lparam, 0, 0 },
5959 { 0 }
5960 };
5961 static const struct message WmKillFocusOwnerdrawSeq[] =
5962 {
5963 { HCBT_SETFOCUS, hook },
5964 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5965 { WM_KILLFOCUS, sent|wparam, 0 },
5966 { WM_CTLCOLORBTN, sent|parent },
5967 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5968 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5969 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5970 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5971 { WM_APP, sent|wparam|lparam, 0, 0 },
5972 { WM_PAINT, sent },
5973 { WM_CTLCOLORBTN, sent|parent },
5974 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5975 { 0 }
5976 };
5977 static const struct message WmLButtonDownSeq[] =
5978 {
5979 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5980 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5981 { HCBT_SETFOCUS, hook },
5982 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5983 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5984 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5985 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5986 { WM_CTLCOLORBTN, sent|defwinproc },
5987 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5988 { WM_CTLCOLORBTN, sent|defwinproc },
5989 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5990 { 0 }
5991 };
5992 static const struct message WmLButtonDownStaticSeq[] =
5993 {
5994 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5995 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5996 { HCBT_SETFOCUS, hook },
5997 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5998 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5999 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6000 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6001 { WM_CTLCOLORSTATIC, sent|defwinproc },
6002 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6003 { WM_CTLCOLORSTATIC, sent|defwinproc },
6004 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6005 { 0 }
6006 };
6007 static const struct message WmLButtonUpSeq[] =
6008 {
6009 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6010 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6011 { WM_CTLCOLORBTN, sent|defwinproc },
6012 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6013 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6014 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6015 { 0 }
6016 };
6017 static const struct message WmLButtonUpStaticSeq[] =
6018 {
6019 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6020 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6021 { WM_CTLCOLORSTATIC, sent|defwinproc },
6022 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6023 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6024 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6025 { 0 }
6026 };
6027 static const struct message WmLButtonUpAutoSeq[] =
6028 {
6029 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6030 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6031 { WM_CTLCOLORSTATIC, sent|defwinproc },
6032 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6033 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6034 { BM_SETCHECK, sent|defwinproc },
6035 { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6036 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6037 { 0 }
6038 };
6039 static const struct message WmLButtonUpBrokenSeq[] =
6040 {
6041 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6042 { 0 }
6043 };
6044 static const struct message WmSetFontButtonSeq[] =
6045 {
6046 { WM_SETFONT, sent },
6047 { WM_PAINT, sent },
6048 { WM_ERASEBKGND, sent|defwinproc|optional },
6049 { WM_CTLCOLORBTN, sent|defwinproc },
6050 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6051 { 0 }
6052 };
6053 static const struct message WmSetFontStaticSeq[] =
6054 {
6055 { WM_SETFONT, sent },
6056 { WM_PAINT, sent },
6057 { WM_ERASEBKGND, sent|defwinproc|optional },
6058 { WM_CTLCOLORSTATIC, sent|defwinproc },
6059 { 0 }
6060 };
6061 static const struct message WmSetTextButtonSeq[] =
6062 {
6063 { WM_SETTEXT, sent },
6064 { WM_CTLCOLORBTN, sent|parent },
6065 { WM_CTLCOLORBTN, sent|parent },
6066 { WM_COMMAND, sent|parent|optional },
6067 { WM_DRAWITEM, sent|parent|optional },
6068 { 0 }
6069 };
6070 static const struct message WmSetTextStaticSeq[] =
6071 {
6072 { WM_SETTEXT, sent },
6073 { WM_CTLCOLORSTATIC, sent|parent },
6074 { WM_CTLCOLORSTATIC, sent|parent },
6075 { 0 }
6076 };
6077 static const struct message WmSetTextGroupSeq[] =
6078 {
6079 { WM_SETTEXT, sent },
6080 { WM_CTLCOLORSTATIC, sent|parent },
6081 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6082 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6083 { 0 }
6084 };
6085 static const struct message WmSetTextInvisibleSeq[] =
6086 {
6087 { WM_SETTEXT, sent },
6088 { 0 }
6089 };
6090 static const struct message WmSetStyleButtonSeq[] =
6091 {
6092 { BM_SETSTYLE, sent },
6093 { WM_APP, sent|wparam|lparam, 0, 0 },
6094 { WM_PAINT, sent },
6095 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6096 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6097 { WM_CTLCOLORBTN, sent|parent },
6098 { 0 }
6099 };
6100 static const struct message WmSetStyleStaticSeq[] =
6101 {
6102 { BM_SETSTYLE, sent },
6103 { WM_APP, sent|wparam|lparam, 0, 0 },
6104 { WM_PAINT, sent },
6105 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6106 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6107 { WM_CTLCOLORSTATIC, sent|parent },
6108 { 0 }
6109 };
6110 static const struct message WmSetStyleUserSeq[] =
6111 {
6112 { BM_SETSTYLE, sent },
6113 { WM_APP, sent|wparam|lparam, 0, 0 },
6114 { WM_PAINT, sent },
6115 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6116 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6117 { WM_CTLCOLORBTN, sent|parent },
6118 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6119 { 0 }
6120 };
6121 static const struct message WmSetStyleOwnerdrawSeq[] =
6122 {
6123 { BM_SETSTYLE, sent },
6124 { WM_APP, sent|wparam|lparam, 0, 0 },
6125 { WM_PAINT, sent },
6126 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6127 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6128 { WM_CTLCOLORBTN, sent|parent },
6129 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6130 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6131 { 0 }
6132 };
6133 static const struct message WmSetStateButtonSeq[] =
6134 {
6135 { BM_SETSTATE, sent },
6136 { WM_CTLCOLORBTN, sent|parent },
6137 { WM_APP, sent|wparam|lparam, 0, 0 },
6138 { 0 }
6139 };
6140 static const struct message WmSetStateStaticSeq[] =
6141 {
6142 { BM_SETSTATE, sent },
6143 { WM_CTLCOLORSTATIC, sent|parent },
6144 { WM_APP, sent|wparam|lparam, 0, 0 },
6145 { 0 }
6146 };
6147 static const struct message WmSetStateUserSeq[] =
6148 {
6149 { BM_SETSTATE, sent },
6150 { WM_CTLCOLORBTN, sent|parent },
6151 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6152 { WM_APP, sent|wparam|lparam, 0, 0 },
6153 { 0 }
6154 };
6155 static const struct message WmSetStateOwnerdrawSeq[] =
6156 {
6157 { BM_SETSTATE, sent },
6158 { WM_CTLCOLORBTN, sent|parent },
6159 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6160 { WM_APP, sent|wparam|lparam, 0, 0 },
6161 { 0 }
6162 };
6163 static const struct message WmClearStateButtonSeq[] =
6164 {
6165 { BM_SETSTATE, sent },
6166 { WM_CTLCOLORBTN, sent|parent },
6167 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6168 { WM_APP, sent|wparam|lparam, 0, 0 },
6169 { 0 }
6170 };
6171 static const struct message WmDisableButtonSeq[] =
6172 {
6173 { WM_LBUTTONDOWN, sent },
6174 { BM_SETSTATE, sent|defwinproc },
6175 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6176 { WM_CTLCOLORBTN, sent|optional },
6177 { WM_LBUTTONUP, sent },
6178 { BM_SETSTATE, sent|defwinproc },
6179 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6180 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6181 { BM_SETCHECK, sent|defwinproc|optional },
6182 { WM_CTLCOLORBTN, sent|optional },
6183 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6184 { WM_CAPTURECHANGED, sent|defwinproc },
6185 { WM_COMMAND, sent },
6186 { 0 }
6187 };
6188 static const struct message WmClearStateOwnerdrawSeq[] =
6189 {
6190 { BM_SETSTATE, sent },
6191 { WM_CTLCOLORBTN, sent|parent },
6192 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6193 { WM_APP, sent|wparam|lparam, 0, 0 },
6194 { 0 }
6195 };
6196 static const struct message WmSetCheckIgnoredSeq[] =
6197 {
6198 { BM_SETCHECK, sent },
6199 { WM_APP, sent|wparam|lparam, 0, 0 },
6200 { 0 }
6201 };
6202 static const struct message WmSetCheckStaticSeq[] =
6203 {
6204 { BM_SETCHECK, sent },
6205 { WM_CTLCOLORSTATIC, sent|parent },
6206 { WM_APP, sent|wparam|lparam, 0, 0 },
6207 { 0 }
6208 };
6209
6210 static WNDPROC old_button_proc;
6211
6212 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6213 {
6214 static LONG defwndproc_counter = 0;
6215 LRESULT ret;
6216 struct recvd_message msg;
6217
6218 if (ignore_message( message )) return 0;
6219
6220 switch (message)
6221 {
6222 case WM_SYNCPAINT:
6223 break;
6224 case BM_SETSTATE:
6225 if (GetCapture())
6226 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6227
6228 lParam = (ULONG_PTR)GetMenu(hwnd);
6229 goto log_it;
6230
6231 case WM_GETDLGCODE:
6232 if (lParam)
6233 {
6234 MSG *msg = (MSG *)lParam;
6235 lParam = MAKELPARAM(msg->message, msg->wParam);
6236 }
6237 wParam = (ULONG_PTR)GetMenu(hwnd);
6238 goto log_it;
6239
6240 case BM_SETCHECK:
6241 case BM_GETCHECK:
6242 lParam = (ULONG_PTR)GetMenu(hwnd);
6243 /* fall through */
6244 log_it:
6245 default:
6246 msg.hwnd = hwnd;
6247 msg.message = message;
6248 msg.flags = sent|wparam|lparam;
6249 if (defwndproc_counter) msg.flags |= defwinproc;
6250 msg.wParam = wParam;
6251 msg.lParam = lParam;
6252 msg.descr = "button";
6253 add_message(&msg);
6254 }
6255
6256 defwndproc_counter++;
6257 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6258 defwndproc_counter--;
6259
6260 return ret;
6261 }
6262
6263 static void subclass_button(void)
6264 {
6265 WNDCLASSA cls;
6266
6267 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6268
6269 old_button_proc = cls.lpfnWndProc;
6270
6271 cls.hInstance = GetModuleHandleA(NULL);
6272 cls.lpfnWndProc = button_hook_proc;
6273 cls.lpszClassName = "my_button_class";
6274 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6275 if (!RegisterClassA(&cls)) assert(0);
6276 }
6277
6278 static void test_button_messages(void)
6279 {
6280 static const struct
6281 {
6282 DWORD style;
6283 DWORD dlg_code;
6284 const struct message *setfocus;
6285 const struct message *killfocus;
6286 const struct message *setstyle;
6287 const struct message *setstate;
6288 const struct message *clearstate;
6289 const struct message *setcheck;
6290 const struct message *lbuttondown;
6291 const struct message *lbuttonup;
6292 const struct message *setfont;
6293 const struct message *settext;
6294 } button[] = {
6295 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6296 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6297 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6298 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6299 WmSetTextButtonSeq },
6300 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6301 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6302 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6303 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6304 WmSetTextButtonSeq },
6305 { BS_CHECKBOX, DLGC_BUTTON,
6306 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6307 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6308 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6309 WmSetTextStaticSeq },
6310 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6311 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6312 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6313 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6314 WmSetTextStaticSeq },
6315 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6316 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6317 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6318 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6319 WmSetTextStaticSeq },
6320 { BS_3STATE, DLGC_BUTTON,
6321 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6322 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6323 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6324 WmSetTextStaticSeq },
6325 { BS_AUTO3STATE, DLGC_BUTTON,
6326 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6327 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6328 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6329 WmSetTextStaticSeq },
6330 { BS_GROUPBOX, DLGC_STATIC,
6331 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6332 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6333 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6334 WmSetTextGroupSeq },
6335 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6336 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6337 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6338 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6339 WmSetTextButtonSeq },
6340 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6341 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6342 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6343 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6344 WmSetTextStaticSeq },
6345 { BS_OWNERDRAW, DLGC_BUTTON,
6346 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6347 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6348 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6349 WmSetTextButtonSeq },
6350 };
6351 LOGFONTA logfont = { 0 };
6352 HFONT zfont, hfont2;
6353 unsigned int i;
6354 HWND hwnd, parent;
6355 DWORD dlg_code;
6356
6357 /* selection with VK_SPACE should capture button window */
6358 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6359 0, 0, 50, 14, 0, 0, 0, NULL);
6360 ok(hwnd != 0, "Failed to create button window\n");
6361 ReleaseCapture();
6362 SetFocus(hwnd);
6363 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6364 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6365 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6366 DestroyWindow(hwnd);
6367
6368 subclass_button();
6369
6370 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6371 100, 100, 200, 200, 0, 0, 0, NULL);
6372 ok(parent != 0, "Failed to create parent window\n");
6373
6374 memset(&logfont, 0, sizeof(logfont));
6375 logfont.lfHeight = -12;
6376 logfont.lfWeight = FW_NORMAL;
6377 strcpy(logfont.lfFaceName, "Tahoma");
6378
6379 hfont2 = CreateFontIndirectA(&logfont);
6380 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6381
6382 for (i = 0; i < ARRAY_SIZE(button); i++)
6383 {
6384 MSG msg;
6385 DWORD style, state;
6386 HFONT prevfont;
6387 char desc[64];
6388 HDC hdc;
6389
6390 trace("button style %08x\n", button[i].style);
6391
6392 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6393 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6394 ok(hwnd != 0, "Failed to create button window\n");
6395
6396 style = GetWindowLongA(hwnd, GWL_STYLE);
6397 style &= ~(WS_CHILD | BS_NOTIFY);
6398 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6399 if (button[i].style == BS_USERBUTTON)
6400 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6401 else
6402 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6403
6404 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6405 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6406
6407 ShowWindow(hwnd, SW_SHOW);
6408 UpdateWindow(hwnd);
6409 SetFocus(0);
6410 flush_events();
6411 SetFocus(0);
6412 flush_sequence();
6413
6414 log_all_parent_messages++;
6415
6416 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6417 SetFocus(hwnd);
6418 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6419 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6420 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6421
6422 SetFocus(0);
6423 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6424 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6425 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6426
6427 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6428
6429 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6430 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6431 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6432 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6433
6434 style = GetWindowLongA(hwnd, GWL_STYLE);
6435 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6436 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6437 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6438
6439 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6440 ok(state == 0, "expected state 0, got %04x\n", state);
6441
6442 flush_sequence();
6443
6444 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6445 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6446 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6447 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6448
6449 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6450 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6451
6452 style = GetWindowLongA(hwnd, GWL_STYLE);
6453 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6454 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6455
6456 flush_sequence();
6457
6458 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6459 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6460 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6461 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6462
6463 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6464 ok(state == 0, "expected state 0, got %04x\n", state);
6465
6466 style = GetWindowLongA(hwnd, GWL_STYLE);
6467 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6468 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6469
6470 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6471 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6472
6473 flush_sequence();
6474
6475 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6476 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6477 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6478 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6479
6480 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6481 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6482
6483 style = GetWindowLongA(hwnd, GWL_STYLE);
6484 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6485 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6486
6487 flush_sequence();
6488
6489 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6490 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6491 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6492 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6493
6494 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6495 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6496 ok_sequence(button[i].settext, desc, FALSE);
6497
6498 ShowWindow(hwnd, SW_HIDE);
6499 flush_events();
6500 flush_sequence();
6501
6502 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6503 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6504 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6505
6506 ShowWindow(hwnd, SW_SHOW);
6507 ShowWindow(parent, SW_HIDE);
6508 flush_events();
6509 flush_sequence();
6510
6511 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6512 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6513 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6514
6515 ShowWindow(parent, SW_SHOW);
6516 flush_events();
6517
6518 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6519 if (button[i].style == BS_PUSHBUTTON ||
6520 button[i].style == BS_DEFPUSHBUTTON ||
6521 button[i].style == BS_GROUPBOX ||
6522 button[i].style == BS_USERBUTTON ||
6523 button[i].style == BS_OWNERDRAW)
6524 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6525 else
6526 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6527
6528 style = GetWindowLongA(hwnd, GWL_STYLE);
6529 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6530 if (button[i].style == BS_RADIOBUTTON ||
6531 button[i].style == BS_AUTORADIOBUTTON)
6532 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6533 else
6534 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6535
6536 log_all_parent_messages--;
6537
6538 DestroyWindow(hwnd);
6539
6540 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6541 0, 0, 50, 14, 0, 0, 0, NULL);
6542 ok(hwnd != 0, "Failed to create button window\n");
6543
6544 SetForegroundWindow(hwnd);
6545 flush_events();
6546
6547 SetActiveWindow(hwnd);
6548 SetFocus(0);
6549 flush_sequence();
6550
6551 if (button[i].lbuttondown)
6552 {
6553 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6554 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6555 ok_sequence(button[i].lbuttondown, desc, FALSE);
6556 }
6557
6558 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6559 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6560 ok_sequence(button[i].lbuttonup, desc, FALSE);
6561
6562 flush_sequence();
6563 zfont = GetStockObject(DEFAULT_GUI_FONT);
6564 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6565 UpdateWindow(hwnd);
6566 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6567 ok_sequence(button[i].setfont, desc, FALSE);
6568
6569 /* Test that original font is not selected back after painting */
6570 hdc = CreateCompatibleDC(0);
6571
6572 prevfont = SelectObject(hdc, hfont2);
6573 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6574 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6575 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6576 SelectObject(hdc, prevfont);
6577
6578 prevfont = SelectObject(hdc, hfont2);
6579 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6580 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6581 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6582 SelectObject(hdc, prevfont);
6583
6584 DeleteDC(hdc);
6585
6586 DestroyWindow(hwnd);
6587 }
6588
6589 DeleteObject(hfont2);
6590 DestroyWindow(parent);
6591
6592 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6593
6594 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6595 100, 100, 200, 200, 0, 0, 0, NULL);
6596 ok (hwnd != 0, "Failed to create overlapped window\n");
6597
6598 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6599 0, 0, 50, 14, parent, 0, 0, NULL);
6600
6601 EnableWindow(hwnd, FALSE);
6602 flush_sequence();
6603 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6604 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6605 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6606
6607 DestroyWindow(hwnd);
6608 DestroyWindow(parent);
6609 }
6610
6611 static void test_button_bm_get_set_image(void)
6612 {
6613 HWND hwnd;
6614 HDC hdc;
6615 HBITMAP hbmp1x1;
6616 HBITMAP hbmp2x2;
6617 HBITMAP hmask2x2;
6618 ICONINFO icon_info2x2;
6619 HICON hicon2x2;
6620 HBITMAP hbmp;
6621 HICON hicon;
6622 ICONINFO icon_info;
6623 BITMAP bm;
6624 DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
6625 LRESULT ret;
6626
6627 hdc = GetDC(0);
6628 hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
6629 hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6630 ZeroMemory(&bm, sizeof(bm));
6631 ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6632 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6633 bm.bmWidth, bm.bmHeight);
6634 ZeroMemory(&bm, sizeof(bm));
6635 ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6636 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6637 bm.bmWidth, bm.bmHeight);
6638
6639 hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6640 ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
6641 icon_info2x2.fIcon = TRUE;
6642 icon_info2x2.hbmMask = hmask2x2;
6643 icon_info2x2.hbmColor = hbmp2x2;
6644 hicon2x2 = CreateIconIndirect(&icon_info2x2);
6645
6646 ZeroMemory(&icon_info, sizeof(icon_info));
6647 ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
6648 ZeroMemory(&bm, sizeof(bm));
6649 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6650 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6651 bm.bmWidth, bm.bmHeight);
6652 DeleteObject(icon_info.hbmColor);
6653 DeleteObject(icon_info.hbmMask);
6654
6655 /* Set bitmap with BS_BITMAP */
6656 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6657 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6658 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6659 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6660 ok(hbmp != 0, "Expect hbmp not 0\n");
6661 ZeroMemory(&bm, sizeof(bm));
6662 ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6663 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6664 bm.bmWidth, bm.bmHeight);
6665 DestroyWindow(hwnd);
6666
6667 /* Set bitmap without BS_BITMAP */
6668 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6669 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6670 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6671 ok(ret == 0, "Expect ret to be 0\n");
6672 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6673 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6674 DestroyWindow(hwnd);
6675
6676 /* Set icon with BS_ICON */
6677 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6678 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6679 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6680 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6681 ok(hicon != NULL, "Expect hicon not NULL\n");
6682 ZeroMemory(&icon_info, sizeof(icon_info));
6683 ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
6684 ZeroMemory(&bm, sizeof(bm));
6685 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6686 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6687 bm.bmWidth, bm.bmHeight);
6688 DeleteObject(icon_info.hbmColor);
6689 DeleteObject(icon_info.hbmMask);
6690 DestroyWindow(hwnd);
6691
6692 /* Set icon without BS_ICON */
6693 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6694 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6695 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6696 ok(ret == 0, "Expect ret to be 0\n");
6697 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6698 ok(hicon == NULL, "Expect hicon to be NULL\n");
6699 DestroyWindow(hwnd);
6700
6701 /* Set icon with BS_BITMAP */
6702 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6703 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6704 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6705 ok(ret == 0, "Expect ret to be 0\n");
6706 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6707 ok(hicon == NULL, "Expect hicon to be NULL\n");
6708 DestroyWindow(hwnd);
6709
6710 /* Set bitmap with BS_ICON */
6711 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6712 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6713 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6714 ok(ret == 0, "Expect ret to be 0\n");
6715 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6716 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6717 DestroyWindow(hwnd);
6718
6719 DestroyIcon(hicon2x2);
6720 DeleteObject(hmask2x2);
6721 DeleteObject(hbmp2x2);
6722 DeleteObject(hbmp1x1);
6723 ReleaseDC(0, hdc);
6724 }
6725
6726 #define ID_RADIO1 501
6727 #define ID_RADIO2 502
6728 #define ID_RADIO3 503
6729 #define ID_TEXT 504
6730
6731 static const struct message auto_radio_button_BM_CLICK[] =
6732 {
6733 { BM_CLICK, sent|wparam|lparam, 0, 0 },
6734 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6735 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6736 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6737 { WM_CTLCOLORSTATIC, sent|parent },
6738 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6739 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6740 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6741 { WM_CTLCOLORSTATIC, sent|parent },
6742 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6743 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6744 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6745 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6746 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
6747 { WM_CTLCOLORSTATIC, sent|parent },
6748 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6749 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6750 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
6751 { WM_CTLCOLORSTATIC, sent|parent },
6752 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6753 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6754 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6755 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6756 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
6757 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6758 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6759 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6760 { 0 }
6761 };
6762
6763 static const struct message auto_radio_button_VK_UP_child[] =
6764 {
6765 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
6766 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
6767 { 0 }
6768 };
6769
6770 static const struct message auto_radio_button_VK_UP_parent[] =
6771 {
6772 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
6773 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
6774 { 0 }
6775 };
6776
6777 static const struct message auto_radio_button_VK_UP_dialog[] =
6778 {
6779 { WM_GETDLGCODE, sent|parent, 0, 0 },
6780
6781 /* optional trailer seen on some windows setups */
6782 { WM_CHANGEUISTATE, sent|optional },
6783 { WM_UPDATEUISTATE, sent|optional },
6784 { WM_UPDATEUISTATE, sent|optional },
6785 { WM_UPDATEUISTATE, sent|optional },
6786 { WM_UPDATEUISTATE, sent|optional },
6787 { WM_UPDATEUISTATE, sent|optional },
6788 { WM_UPDATEUISTATE, sent|optional },
6789 { WM_UPDATEUISTATE, sent|optional },
6790 { WM_UPDATEUISTATE, sent|optional },
6791 { WM_UPDATEUISTATE, sent|optional },
6792 { WM_UPDATEUISTATE, sent|optional },
6793 { WM_UPDATEUISTATE, sent|optional },
6794 { WM_UPDATEUISTATE, sent|optional },
6795 { WM_UPDATEUISTATE, sent|optional },
6796 { WM_UPDATEUISTATE, sent|optional },
6797 { WM_UPDATEUISTATE, sent|optional },
6798 { WM_UPDATEUISTATE, sent|optional },
6799 { WM_UPDATEUISTATE, sent|optional },
6800 { WM_UPDATEUISTATE, sent|optional },
6801 { WM_CTLCOLORSTATIC, sent|parent|optional },
6802 { WM_CTLCOLORSTATIC, sent|parent|optional },
6803 { WM_CTLCOLORSTATIC, sent|parent|optional },
6804 { WM_UPDATEUISTATE, sent|optional },
6805 { WM_CTLCOLORSTATIC, sent|parent|optional },
6806 { WM_CTLCOLORSTATIC, sent|parent|optional },
6807 { WM_UPDATEUISTATE, sent|optional },
6808 { WM_CTLCOLORBTN, sent|parent|optional },
6809 { WM_CTLCOLORBTN, sent|parent|optional },
6810 { WM_UPDATEUISTATE, sent|optional },
6811 { WM_CTLCOLORSTATIC, sent|parent|optional },
6812 { WM_CTLCOLORSTATIC, sent|parent|optional },
6813 { 0 }
6814 };
6815
6816 static const struct message auto_radio_button_VK_DOWN_dialog[] =
6817 {
6818 { WM_GETDLGCODE, sent|parent, 0, 0 },
6819 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6820 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6821 { HCBT_SETFOCUS, hook },
6822 { WM_KILLFOCUS, sent, 0, 0 },
6823 { WM_CTLCOLORSTATIC, sent|parent },
6824 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
6825 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6826 { WM_SETFOCUS, sent, 0, 0 },
6827 { WM_CTLCOLORSTATIC, sent|parent },
6828 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
6829 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6830 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6831 { WM_GETDLGCODE, sent|parent, 0, 0 },
6832 { DM_GETDEFID, sent|parent, 0, 0 },
6833 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6834 { BM_CLICK, sent|wparam|lparam, 1, 0 },
6835 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6836 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6837 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6838 { WM_CTLCOLORSTATIC, sent|parent },
6839 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6840 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6841 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
6842 { WM_CTLCOLORSTATIC, sent|parent },
6843 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6844 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6845 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6846 { WM_CTLCOLORSTATIC, sent|parent },
6847 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6848 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6849 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
6850 { WM_CTLCOLORSTATIC, sent|parent },
6851 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6852 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6853 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6854 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6855 { WM_CTLCOLORSTATIC, sent|parent },
6856 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6857 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6858 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6859 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6860 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6861 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6862 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6863 { WM_PAINT, sent },
6864 { WM_CTLCOLORSTATIC, sent|parent },
6865 { 0 }
6866 };
6867
6868 static const struct message auto_radio_button_VK_DOWN_radio3[] =
6869 {
6870 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6871 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
6872 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
6873 { WM_GETDLGCODE, sent|parent, 0, 0 },
6874 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6875 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6876 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6877 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
6878 { WM_USER, sent|parent, 0, 0 },
6879 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6880 { 0 }
6881 };
6882
6883 static const struct message auto_radio_button_VK_UP_radio1[] =
6884 {
6885 { WM_GETDLGCODE, sent|parent, 0, 0 },
6886 { 0 }
6887 };
6888
6889 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
6890 {
6891 ParentMsgCheckProcA(hwnd, msg, wp, lp);
6892 return 1;
6893 }
6894
6895 static void test_autoradio_BM_CLICK(void)
6896 {
6897 HWND parent, radio1, radio2, radio3;
6898 RECT rc;
6899 MSG msg;
6900 DWORD ret;
6901
6902 subclass_button();
6903
6904 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
6905 ok(parent != 0, "failed to create parent window\n");
6906
6907 radio1 = GetDlgItem(parent, ID_RADIO1);
6908 radio2 = GetDlgItem(parent, ID_RADIO2);
6909 radio3 = GetDlgItem(parent, ID_RADIO3);
6910
6911 /* this avoids focus messages in the generated sequence */
6912 SetFocus(radio2);
6913
6914 flush_events();
6915 flush_sequence();
6916
6917 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6918 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6919 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6920 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6921 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6922 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6923
6924 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
6925
6926 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6927 ok(ret == BST_CHECKED, "got %08x\n", ret);
6928 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6929 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6930 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6931 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6932
6933 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
6934
6935 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6936 ok(ret == BST_CHECKED, "got %08x\n", ret);
6937 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6938 ok(ret == BST_CHECKED, "got %08x\n", ret);
6939 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6940 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6941
6942 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
6943
6944 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6945 ok(ret == BST_CHECKED, "got %08x\n", ret);
6946 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6947 ok(ret == BST_CHECKED, "got %08x\n", ret);
6948 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6949 ok(ret == BST_CHECKED, "got %08x\n", ret);
6950
6951 GetWindowRect(radio2, &rc);
6952 SetCursorPos(rc.left+1, rc.top+1);
6953
6954 flush_events();
6955 flush_sequence();
6956
6957 log_all_parent_messages++;
6958
6959 SendMessageA(radio2, BM_CLICK, 0, 0);
6960 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6961 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
6962
6963 log_all_parent_messages--;
6964
6965 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6966 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6967 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6968 ok(ret == BST_CHECKED, "got %08x\n", ret);
6969 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6970 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6971
6972 DestroyWindow(parent);
6973 }
6974
6975 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
6976 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
6977 {
6978 DWORD ret;
6979
6980 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6981 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6982 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6983 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6984 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6985 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6986 }
6987
6988 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
6989 {
6990 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
6991 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
6992 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
6993 }
6994
6995 static void test_autoradio_kbd_move(void)
6996 {
6997 HWND parent, radio1, radio2, radio3, hwnd;
6998 RECT rc;
6999 MSG msg;
7000 DWORD ret;
7001
7002 subclass_button();
7003
7004 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
7005 ok(parent != 0, "failed to create parent window\n");
7006
7007 radio1 = GetDlgItem(parent, ID_RADIO1);
7008 radio2 = GetDlgItem(parent, ID_RADIO2);
7009 radio3 = GetDlgItem(parent, ID_RADIO3);
7010
7011 flush_events();
7012 flush_sequence();
7013
7014 test_radio(radio1, 0, radio2, 0, radio3, 0);
7015 set_radio(radio1, 1, radio2, 1, radio3, 1);
7016 test_radio(radio1, 1, radio2, 1, radio3, 1);
7017
7018 SetFocus(radio3);
7019
7020 flush_events();
7021 flush_sequence();
7022
7023 log_all_parent_messages++;
7024
7025 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
7026 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
7027 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7028 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
7029
7030 test_radio(radio1, 1, radio2, 1, radio3, 1);
7031
7032 flush_events();
7033 flush_sequence();
7034
7035 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
7036 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
7037 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7038 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
7039
7040 test_radio(radio1, 1, radio2, 1, radio3, 1);
7041
7042 SetFocus(radio3);
7043 GetWindowRect(radio3, &rc);
7044
7045 flush_events();
7046 flush_sequence();
7047
7048 msg.hwnd = parent;
7049 msg.message = WM_KEYDOWN;
7050 msg.wParam = VK_UP;
7051 msg.lParam = 0;
7052 msg.pt.x = rc.left + 1;
7053 msg.pt.y = rc.top + 1;
7054 ret = IsDialogMessageA(parent, &msg);
7055 ok(ret, "IsDialogMessage should return TRUE\n");
7056 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7057 if (0) /* actual message sequence is different on every run in some Windows setups */
7058 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
7059 /* what really matters is that nothing has changed */
7060 test_radio(radio1, 1, radio2, 1, radio3, 1);
7061
7062 set_radio(radio1, 0, radio2, 1, radio3, 1);
7063 test_radio(radio1, 0, radio2, 1, radio3, 1);
7064
7065 flush_events();
7066 flush_sequence();
7067
7068 ret = IsDialogMessageA(parent, &msg);
7069 ok(ret, "IsDialogMessage should return TRUE\n");
7070 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7071 if (0) /* actual message sequence is different on every run in some Windows setups */
7072 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
7073 /* what really matters is that nothing has changed */
7074 test_radio(radio1, 0, radio2, 1, radio3, 1);
7075
7076 /* switch from radio3 ro radio1 */
7077 SetFocus(radio3);
7078 GetWindowRect(radio3, &rc);
7079
7080 flush_events();
7081 flush_sequence();
7082
7083 msg.hwnd = parent;
7084 msg.message = WM_KEYDOWN;
7085 msg.wParam = VK_DOWN;
7086 msg.lParam = 0;
7087 msg.pt.x = rc.left + 1;
7088 msg.pt.y = rc.top + 1;
7089 ret = IsDialogMessageA(parent, &msg);
7090 ok(ret, "IsDialogMessage should return TRUE\n");
7091 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7092 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
7093
7094 test_radio(radio1, 1, radio2, 0, radio3, 0);
7095
7096 hwnd = GetFocus();
7097 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7098 GetWindowRect(radio1, &rc);
7099
7100 msg.hwnd = parent;
7101 msg.message = WM_KEYDOWN;
7102 msg.wParam = VK_DOWN;
7103 msg.lParam = 0;
7104 msg.pt.x = rc.left + 1;
7105 msg.pt.y = rc.top + 1;
7106 ret = IsDialogMessageA(parent, &msg);
7107 ok(ret, "IsDialogMessage should return TRUE\n");
7108 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7109 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7110
7111 test_radio(radio1, 1, radio2, 0, radio3, 0);
7112
7113 hwnd = GetFocus();
7114 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7115
7116 flush_events();
7117 flush_sequence();
7118
7119 msg.hwnd = parent;
7120 msg.message = WM_KEYDOWN;
7121 msg.wParam = VK_UP;
7122 msg.lParam = 0;
7123 msg.pt.x = rc.left + 1;
7124 msg.pt.y = rc.top + 1;
7125 ret = IsDialogMessageA(parent, &msg);
7126 ok(ret, "IsDialogMessage should return TRUE\n");
7127 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7128 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7129
7130 test_radio(radio1, 1, radio2, 0, radio3, 0);
7131
7132 hwnd = GetFocus();
7133 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7134
7135 flush_events();
7136 flush_sequence();
7137
7138 msg.hwnd = parent;
7139 msg.message = WM_KEYDOWN;
7140 msg.wParam = VK_UP;
7141 msg.lParam = 0;
7142 msg.pt.x = rc.left + 1;
7143 msg.pt.y = rc.top + 1;
7144 ret = IsDialogMessageA(parent, &msg);
7145 ok(ret, "IsDialogMessage should return TRUE\n");
7146 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7147 if (0) /* actual message sequence is different on every run in some Windows setups */
7148 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7149 /* what really matters is that nothing has changed */
7150 test_radio(radio1, 1, radio2, 0, radio3, 0);
7151
7152 log_all_parent_messages--;
7153
7154 DestroyWindow(parent);
7155 }
7156
7157 /****************** static message test *************************/
7158 static const struct message WmSetFontStaticSeq2[] =
7159 {
7160 { WM_SETFONT, sent },
7161 { WM_PAINT, sent|defwinproc|optional },
7162 { WM_ERASEBKGND, sent|defwinproc|optional },
7163 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7164 { 0 }
7165 };
7166
7167 static WNDPROC old_static_proc;
7168
7169 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7170 {
7171 static LONG defwndproc_counter = 0;
7172 LRESULT ret;
7173 struct recvd_message msg;
7174
7175 if (ignore_message( message )) return 0;
7176
7177 msg.hwnd = hwnd;
7178 msg.message = message;
7179 msg.flags = sent|wparam|lparam;
7180 if (defwndproc_counter) msg.flags |= defwinproc;
7181 msg.wParam = wParam;
7182 msg.lParam = lParam;
7183 msg.descr = "static";
7184 add_message(&msg);
7185
7186 defwndproc_counter++;
7187 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7188 defwndproc_counter--;
7189
7190 return ret;
7191 }
7192
7193 static void subclass_static(void)
7194 {
7195 WNDCLASSA cls;
7196
7197 if (!GetClassInfoA(0, "static", &cls)) assert(0);
7198
7199 old_static_proc = cls.lpfnWndProc;
7200
7201 cls.hInstance = GetModuleHandleA(NULL);
7202 cls.lpfnWndProc = static_hook_proc;
7203 cls.lpszClassName = "my_static_class";
7204 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7205 if (!RegisterClassA(&cls)) assert(0);
7206 }
7207
7208 static void test_static_messages(void)
7209 {
7210 /* FIXME: make as comprehensive as the button message test */
7211 static const struct
7212 {
7213 DWORD style;
7214 DWORD dlg_code;
7215 const struct message *setfont;
7216 } static_ctrl[] = {
7217 { SS_LEFT, DLGC_STATIC,
7218 WmSetFontStaticSeq2 }
7219 };
7220 unsigned int i;
7221 HWND hwnd;
7222 DWORD dlg_code;
7223
7224 subclass_static();
7225
7226 for (i = 0; i < ARRAY_SIZE(static_ctrl); i++)
7227 {
7228 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7229 0, 0, 50, 14, 0, 0, 0, NULL);
7230 ok(hwnd != 0, "Failed to create static window\n");
7231
7232 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7233 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7234
7235 ShowWindow(hwnd, SW_SHOW);
7236 UpdateWindow(hwnd);
7237 SetFocus(0);
7238 flush_sequence();
7239
7240 trace("static style %08x\n", static_ctrl[i].style);
7241 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7242 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7243
7244 DestroyWindow(hwnd);
7245 }
7246 }
7247
7248 /****************** ComboBox message test *************************/
7249 #define ID_COMBOBOX 0x000f
7250
7251 static const struct message SetCurSelComboSeq[] =
7252 {
7253 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7254 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7255 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7256 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7257 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7258 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7259 { LB_GETTEXT, sent|wparam, 0 },
7260 { WM_CTLCOLOREDIT, sent|parent },
7261 { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7262 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7263 { 0 }
7264 };
7265
7266 static const struct message SetCurSelComboSeq2[] =
7267 {
7268 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7269 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7270 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7271 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7272 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7273 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7274 { LB_GETTEXT, sent|wparam, 0 },
7275 { 0 }
7276 };
7277
7278 static const struct message SetCurSelComboSeq_edit[] =
7279 {
7280 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7281 { WM_SETTEXT, sent|wparam, 0 },
7282 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7283 { 0 }
7284 };
7285
7286 static const struct message WmKeyDownComboSeq[] =
7287 {
7288 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7289 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7290 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7291 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7292 { WM_CTLCOLOREDIT, sent|parent },
7293 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7294 { 0 }
7295 };
7296
7297 static const struct message WmSetPosComboSeq[] =
7298 {
7299 { WM_WINDOWPOSCHANGING, sent },
7300 { WM_NCCALCSIZE, sent|wparam, TRUE },
7301 { WM_CHILDACTIVATE, sent },
7302 { WM_WINDOWPOSCHANGED, sent },
7303 { WM_MOVE, sent|defwinproc },
7304 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7305 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7306 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7307 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7308 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7309 { 0 }
7310 };
7311
7312 static const struct message WMSetFocusComboBoxSeq[] =
7313 {
7314 { WM_SETFOCUS, sent },
7315 { WM_KILLFOCUS, sent|parent },
7316 { WM_SETFOCUS, sent },
7317 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7318 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7319 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7320 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7321 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7322 { 0 }
7323 };
7324
7325 static const struct message SetFocusButtonSeq[] =
7326 {
7327 { WM_KILLFOCUS, sent },
7328 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7329 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7330 { WM_LBUTTONUP, sent|defwinproc },
7331 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7332 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7333 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7334 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7335 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7336 { WM_CTLCOLORBTN, sent|parent },
7337 { 0 }
7338 };
7339
7340 static const struct message SetFocusComboBoxSeq[] =
7341 {
7342 { WM_CTLCOLORBTN, sent|parent },
7343 { WM_SETFOCUS, sent },
7344 { WM_KILLFOCUS, sent|defwinproc },
7345 { WM_SETFOCUS, sent },
7346 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7347 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7348 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7349 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7350 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7351 { 0 }
7352 };
7353
7354 static const struct message SetFocusButtonSeq2[] =
7355 {
7356 { WM_KILLFOCUS, sent },
7357 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7358 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7359 { WM_LBUTTONUP, sent|defwinproc },
7360 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7361 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7362 { WM_CTLCOLOREDIT, sent|defwinproc },
7363 { WM_CTLCOLOREDIT, sent|parent },
7364 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7365 { WM_CTLCOLORBTN, sent|parent },
7366 { 0 }
7367 };
7368
7369 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7370
7371 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7372 WPARAM wParam, LPARAM lParam)
7373 {
7374 static LONG defwndproc_counter = 0;
7375 LRESULT ret;
7376 struct recvd_message msg;
7377
7378 /* do not log painting messages */
7379 if (message != WM_PAINT &&
7380 message != WM_NCPAINT &&
7381 message != WM_SYNCPAINT &&
7382 message != WM_ERASEBKGND &&
7383 message != WM_NCHITTEST &&
7384 message != WM_GETTEXT &&
7385 !ignore_message( message ))
7386 {
7387 msg.hwnd = hwnd;
7388 msg.message = message;
7389 msg.flags = sent|wparam|lparam;
7390 if (defwndproc_counter) msg.flags |= defwinproc;
7391 msg.wParam = wParam;
7392 msg.lParam = lParam;
7393 msg.descr = "combo edit";
7394 add_message(&msg);
7395 }
7396
7397 defwndproc_counter++;
7398 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7399 defwndproc_counter--;
7400
7401 return ret;
7402 }
7403
7404 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7405 WPARAM wParam, LPARAM lParam)
7406 {
7407 static LONG defwndproc_counter = 0;
7408 LRESULT ret;
7409 struct recvd_message msg;
7410
7411 /* do not log painting messages */
7412 if (message != WM_PAINT &&
7413 message != WM_NCPAINT &&
7414 message != WM_SYNCPAINT &&
7415 message != WM_ERASEBKGND &&
7416 message != WM_NCHITTEST &&
7417 !ignore_message( message ))
7418 {
7419 msg.hwnd = hwnd;
7420 msg.message = message;
7421 msg.flags = sent|wparam|lparam;
7422 if (defwndproc_counter) msg.flags |= defwinproc;
7423 msg.wParam = wParam;
7424 msg.lParam = lParam;
7425 msg.descr = "combo lbox";
7426 add_message(&msg);
7427 }
7428
7429 defwndproc_counter++;
7430 ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7431 defwndproc_counter--;
7432
7433 return ret;
7434 }
7435
7436 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7437 {
7438 static LONG defwndproc_counter = 0;
7439 LRESULT ret;
7440 struct recvd_message msg;
7441
7442 /* do not log painting messages */
7443 if (message != WM_PAINT &&
7444 message != WM_NCPAINT &&
7445 message != WM_SYNCPAINT &&
7446 message != WM_ERASEBKGND &&
7447 message != WM_NCHITTEST &&
7448 message != WM_GETTEXT &&
7449 !ignore_message( message ))
7450 {
7451 msg.hwnd = hwnd;
7452 msg.message = message;
7453 msg.flags = sent|wparam|lparam;
7454 if (defwndproc_counter) msg.flags |= defwinproc;
7455 msg.wParam = wParam;
7456 msg.lParam = lParam;
7457 msg.descr = "combo";
7458 add_message(&msg);
7459 }
7460
7461 defwndproc_counter++;
7462 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7463 defwndproc_counter--;
7464
7465 return ret;
7466 }
7467
7468 static void subclass_combobox(void)
7469 {
7470 WNDCLASSA cls;
7471
7472 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7473
7474 old_combobox_proc = cls.lpfnWndProc;
7475
7476 cls.hInstance = GetModuleHandleA(NULL);
7477 cls.lpfnWndProc = combobox_hook_proc;
7478 cls.lpszClassName = "my_combobox_class";
7479 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7480 if (!RegisterClassA(&cls)) assert(0);
7481 }
7482
7483 static void test_combobox_messages(void)
7484 {
7485 HWND parent, combo, button, edit, lbox;
7486 LRESULT ret;
7487 COMBOBOXINFO cbInfo;
7488 BOOL res;
7489
7490 subclass_combobox();
7491
7492 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7493 100, 100, 200, 200, 0, 0, 0, NULL);
7494 ok(parent != 0, "Failed to create parent window\n");
7495 flush_sequence();
7496
7497 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7498 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7499 ok(combo != 0, "Failed to create combobox window\n");
7500
7501 UpdateWindow(combo);
7502
7503 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7504 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7505
7506 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7507 ok(ret == 0, "expected 0, got %ld\n", ret);
7508 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7509 ok(ret == 1, "expected 1, got %ld\n", ret);
7510 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7511 ok(ret == 2, "expected 2, got %ld\n", ret);
7512
7513 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7514 SetFocus(combo);
7515 flush_sequence();
7516
7517 log_all_parent_messages++;
7518 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7519 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7520 log_all_parent_messages--;
7521 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7522
7523 flush_sequence();
7524 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7525 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7526
7527 DestroyWindow(combo);
7528 DestroyWindow(parent);
7529
7530 /* Start again. Test combobox text selection when getting and losing focus */
7531 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7532 10, 10, 300, 300, NULL, NULL, NULL, NULL);
7533 ok(parent != 0, "Failed to create parent window\n");
7534
7535 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7536 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7537 ok(combo != 0, "Failed to create combobox window\n");
7538
7539 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7540 SetLastError(0xdeadbeef);
7541 res = GetComboBoxInfo(combo, &cbInfo);
7542 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7543 edit = cbInfo.hwndItem;
7544
7545 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
7546 (ULONG_PTR)combobox_edit_subclass_proc);
7547
7548 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7549 5, 50, 100, 20, parent, NULL,
7550 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7551 ok(button != 0, "Failed to create button window\n");
7552
7553 flush_sequence();
7554 log_all_parent_messages++;
7555 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7556 log_all_parent_messages--;
7557 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7558
7559 flush_sequence();
7560 log_all_parent_messages++;
7561 SetFocus(button);
7562 log_all_parent_messages--;
7563 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7564
7565 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7566
7567 flush_sequence();
7568 log_all_parent_messages++;
7569 SetFocus(combo);
7570 log_all_parent_messages--;
7571 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7572
7573 flush_sequence();
7574 log_all_parent_messages++;
7575 SetFocus(button);
7576 log_all_parent_messages--;
7577 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7578
7579 SetFocus(combo);
7580 SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
7581 flush_sequence();
7582 log_all_parent_messages++;
7583 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7584 log_all_parent_messages--;
7585 ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
7586
7587 DestroyWindow(button);
7588 DestroyWindow(combo);
7589
7590 combo = CreateWindowExA(0, "my_combobox_class", "test",
7591 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
7592 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7593 ok(combo != 0, "Failed to create combobox window\n");
7594
7595 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7596 ok(ret == 0, "expected 0, got %ld\n", ret);
7597
7598 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7599 SetLastError(0xdeadbeef);
7600 res = GetComboBoxInfo(combo, &cbInfo);
7601 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7602 lbox = cbInfo.hwndList;
7603 lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
7604 (ULONG_PTR)combobox_lbox_subclass_proc);
7605 flush_sequence();
7606
7607 log_all_parent_messages++;
7608 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7609 log_all_parent_messages--;
7610 ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
7611
7612 ShowWindow(combo, SW_HIDE);
7613 flush_sequence();
7614 log_all_parent_messages++;
7615 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7616 log_all_parent_messages--;
7617 ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
7618
7619 DestroyWindow(combo);
7620 DestroyWindow(parent);
7621 }
7622
7623 /****************** WM_IME_KEYDOWN message test *******************/
7624
7625 static const struct message WmImeKeydownMsgSeq_0[] =
7626 {
7627 { WM_IME_KEYDOWN, wparam, VK_RETURN },
7628 { WM_CHAR, wparam, 'A' },
7629 { 0 }
7630 };
7631
7632 static const struct message WmImeKeydownMsgSeq_1[] =
7633 {
7634 { WM_KEYDOWN, optional|wparam, VK_RETURN },
7635 { WM_CHAR, optional|wparam, VK_RETURN },
7636 { 0 }
7637 };
7638
7639 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7640 {
7641 struct recvd_message msg;
7642
7643 msg.hwnd = hwnd;
7644 msg.message = message;
7645 msg.flags = wparam|lparam;
7646 msg.wParam = wParam;
7647 msg.lParam = lParam;
7648 msg.descr = "wmime_keydown";
7649 add_message(&msg);
7650
7651 return DefWindowProcA(hwnd, message, wParam, lParam);
7652 }
7653
7654 static void register_wmime_keydown_class(void)
7655 {
7656 WNDCLASSA cls;
7657
7658 ZeroMemory(&cls, sizeof(WNDCLASSA));
7659 cls.lpfnWndProc = wmime_keydown_procA;
7660 cls.hInstance = GetModuleHandleA(0);
7661 cls.lpszClassName = "wmime_keydown_class";
7662 if (!RegisterClassA(&cls)) assert(0);
7663 }
7664
7665 static void test_wmime_keydown_message(void)
7666 {
7667 HWND hwnd;
7668 MSG msg;
7669
7670 trace("Message sequences by WM_IME_KEYDOWN\n");
7671
7672 register_wmime_keydown_class();
7673 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7674 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7675 NULL, NULL, 0);
7676 flush_events();
7677 flush_sequence();
7678
7679 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7680 SendMessageA(hwnd, WM_CHAR, 'A', 1);
7681 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7682
7683 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7684 {
7685 TranslateMessage(&msg);
7686 DispatchMessageA(&msg);
7687 }
7688 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7689
7690 DestroyWindow(hwnd);
7691 }
7692
7693 /************* painting message test ********************/
7694
7695 void dump_region(HRGN hrgn)
7696 {
7697 DWORD i, size;
7698 RGNDATA *data = NULL;
7699 RECT *rect;
7700
7701 if (!hrgn)
7702 {
7703 printf( "null region\n" );
7704 return;
7705 }
7706 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7707 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7708 GetRegionData( hrgn, size, data );
7709 printf("%d rects:", data->rdh.nCount );
7710 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7711 printf( " %s", wine_dbgstr_rect( rect ));
7712 printf("\n");
7713 HeapFree( GetProcessHeap(), 0, data );
7714 }
7715
7716 #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn )
7717 static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn )
7718 {
7719 INT ret;
7720 RECT r1, r2;
7721 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7722 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7723
7724 ret = GetUpdateRgn( hwnd, update, FALSE );
7725 ok( ret != ERROR, "GetUpdateRgn failed\n" );
7726 if (ret == NULLREGION)
7727 {
7728 ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" );
7729 }
7730 else
7731 {
7732 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7733 {
7734 ok_(__FILE__,line)( 0, "Regions are different\n" );
7735 if (winetest_debug > 0)
7736 {
7737 printf( "Update region: " );
7738 dump_region( update );
7739 printf( "Wanted region: " );
7740 dump_region( hrgn );
7741 }
7742 }
7743 }
7744 GetRgnBox( update, &r1 );
7745 GetUpdateRect( hwnd, &r2, FALSE );
7746 ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n",
7747 wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 ));
7748
7749 DeleteObject( tmp );
7750 DeleteObject( update );
7751 }
7752
7753 static const struct message WmInvalidateRgn[] = {
7754 { WM_NCPAINT, sent },
7755 { WM_GETTEXT, sent|defwinproc|optional },
7756 { 0 }
7757 };
7758
7759 static const struct message WmGetUpdateRect[] = {
7760 { WM_NCPAINT, sent },
7761 { WM_GETTEXT, sent|defwinproc|optional },
7762 { WM_PAINT, sent },
7763 { 0 }
7764 };
7765
7766 static const struct message WmInvalidateFull[] = {
7767 { WM_NCPAINT, sent|wparam, 1 },
7768 { WM_GETTEXT, sent|defwinproc|optional },
7769 { 0 }
7770 };
7771
7772 static const struct message WmInvalidateErase[] = {
7773 { WM_NCPAINT, sent|wparam, 1 },
7774 { WM_GETTEXT, sent|defwinproc|optional },
7775 { WM_ERASEBKGND, sent },
7776 { 0 }
7777 };
7778
7779 static const struct message WmInvalidatePaint[] = {
7780 { WM_PAINT, sent },
7781 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7782 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7783 { 0 }
7784 };
7785
7786 static const struct message WmInvalidateErasePaint[] = {
7787 { WM_PAINT, sent },
7788 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7789 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7790 { WM_ERASEBKGND, sent|beginpaint|optional },
7791 { 0 }
7792 };
7793
7794 static const struct message WmInvalidateErasePaint2[] = {
7795 { WM_PAINT, sent },
7796 { WM_NCPAINT, sent|beginpaint },
7797 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7798 { WM_ERASEBKGND, sent|beginpaint|optional },
7799 { 0 }
7800 };
7801
7802 static const struct message WmErase[] = {
7803 { WM_ERASEBKGND, sent },
7804 { 0 }
7805 };
7806
7807 static const struct message WmPaint[] = {
7808 { WM_PAINT, sent },
7809 { 0 }
7810 };
7811
7812 static const struct message WmParentOnlyPaint[] = {
7813 { WM_PAINT, sent|parent },
7814 { 0 }
7815 };
7816
7817 static const struct message WmInvalidateParent[] = {
7818 { WM_NCPAINT, sent|parent },
7819 { WM_GETTEXT, sent|defwinproc|parent|optional },
7820 { WM_ERASEBKGND, sent|parent },
7821 { 0 }
7822 };
7823
7824 static const struct message WmInvalidateParentChild[] = {
7825 { WM_NCPAINT, sent|parent },
7826 { WM_GETTEXT, sent|defwinproc|parent|optional },
7827 { WM_ERASEBKGND, sent|parent },
7828 { WM_NCPAINT, sent },
7829 { WM_GETTEXT, sent|defwinproc|optional },
7830 { WM_ERASEBKGND, sent },
7831 { 0 }
7832 };
7833
7834 static const struct message WmInvalidateParentChild2[] = {
7835 { WM_ERASEBKGND, sent|parent },
7836 { WM_NCPAINT, sent },
7837 { WM_GETTEXT, sent|defwinproc|optional },
7838 { WM_ERASEBKGND, sent },
7839 { 0 }
7840 };
7841
7842 static const struct message WmParentPaint[] = {
7843 { WM_PAINT, sent|parent },
7844 { WM_PAINT, sent },
7845 { 0 }
7846 };
7847
7848 static const struct message WmParentPaintNc[] = {
7849 { WM_PAINT, sent|parent },
7850 { WM_PAINT, sent },
7851 { WM_NCPAINT, sent|beginpaint },
7852 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7853 { WM_ERASEBKGND, sent|beginpaint|optional },
7854 { 0 }
7855 };
7856
7857 static const struct message WmChildPaintNc[] = {
7858 { WM_PAINT, sent },
7859 { WM_NCPAINT, sent|beginpaint },
7860 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7861 { WM_ERASEBKGND, sent|beginpaint|optional },
7862 { 0 }
7863 };
7864
7865 static const struct message WmParentErasePaint[] = {
7866 { WM_PAINT, sent|parent },
7867 { WM_NCPAINT, sent|parent|beginpaint },
7868 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7869 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7870 { WM_PAINT, sent },
7871 { WM_NCPAINT, sent|beginpaint },
7872 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7873 { WM_ERASEBKGND, sent|beginpaint|optional },
7874 { 0 }
7875 };
7876
7877 static const struct message WmParentOnlyNcPaint[] = {
7878 { WM_PAINT, sent|parent },
7879 { WM_NCPAINT, sent|parent|beginpaint },
7880 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7881 { 0 }
7882 };
7883
7884 static const struct message WmSetParentStyle[] = {
7885 { WM_STYLECHANGING, sent|parent },
7886 { WM_STYLECHANGED, sent|parent },
7887 { 0 }
7888 };
7889
7890 static void test_paint_messages(void)
7891 {
7892 BOOL ret;
7893 RECT rect, rect2;
7894 POINT pt;
7895 MSG msg;
7896 HWND hparent, hchild;
7897 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7898 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7899 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7900 100, 100, 200, 200, 0, 0, 0, NULL);
7901 ok (hwnd != 0, "Failed to create overlapped window\n");
7902
7903 ShowWindow( hwnd, SW_SHOW );
7904 UpdateWindow( hwnd );
7905 flush_events();
7906 flush_sequence();
7907
7908 check_update_rgn( hwnd, 0 );
7909 SetRectRgn( hrgn, 10, 10, 20, 20 );
7910 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7911 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7912 check_update_rgn( hwnd, hrgn );
7913 SetRectRgn( hrgn2, 20, 20, 30, 30 );
7914 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7915 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7916 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7917 check_update_rgn( hwnd, hrgn );
7918 /* validate everything */
7919 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7920 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7921 check_update_rgn( hwnd, 0 );
7922
7923 /* test empty region */
7924 SetRectRgn( hrgn, 10, 10, 10, 15 );
7925 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7926 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7927 check_update_rgn( hwnd, 0 );
7928 /* test empty rect */
7929 SetRect( &rect, 10, 10, 10, 15 );
7930 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7931 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7932 check_update_rgn( hwnd, 0 );
7933
7934 /* flush pending messages */
7935 flush_events();
7936 flush_sequence();
7937
7938 GetClientRect( hwnd, &rect );
7939 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7940 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7941 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7942 */
7943 SetRectEmpty( &rect );
7944 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n");
7945 check_update_rgn( hwnd, hrgn );
7946 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7947 flush_events();
7948 ok_sequence( WmPaint, "Paint", FALSE );
7949 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7950 check_update_rgn( hwnd, 0 );
7951
7952 SetRectEmpty( &rect );
7953 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7954 "RedrawWindow failed\n");
7955 check_update_rgn( hwnd, 0 );
7956
7957 SetRectEmpty( &rect );
7958 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7959 "RedrawWindow failed\n");
7960 check_update_rgn( hwnd, 0 );
7961
7962 GetWindowRect( hwnd, &rect );
7963 ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7964 "RedrawWindow failed\n");
7965 check_update_rgn( hwnd, 0 );
7966
7967 flush_events();
7968 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7969 "RedrawWindow failed\n");
7970 check_update_rgn( hwnd, hrgn );
7971 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7972 flush_events();
7973 ok_sequence( WmPaint, "Paint", FALSE );
7974 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7975 check_update_rgn( hwnd, 0 );
7976
7977 ok(RedrawWindow(GetDesktopWindow(), &rect, 0,
7978 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7979 "RedrawWindow failed\n");
7980 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
7981 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
7982 "region should be null (%d)\n", ret );
7983 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7984 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7985 flush_events();
7986
7987 ok(RedrawWindow(GetDesktopWindow(), NULL, 0,
7988 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7989 "RedrawWindow failed\n");
7990 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
7991 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
7992 "region should be null (%d)\n", ret );
7993 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7994 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7995 flush_events();
7996
7997 SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom );
7998 ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
7999 "RedrawWindow failed\n");
8000 check_update_rgn( hwnd, hrgn );
8001 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8002 flush_events();
8003 ok_sequence( WmPaint, "Paint", FALSE );
8004 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8005 check_update_rgn( hwnd, 0 );
8006
8007 ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8008 "RedrawWindow failed\n");
8009 check_update_rgn( hwnd, 0 );
8010
8011 ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8012 "RedrawWindow failed\n");
8013 check_update_rgn( hwnd, hrgn );
8014 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8015 flush_events();
8016 ok_sequence( WmPaint, "Paint", FALSE );
8017 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8018 check_update_rgn( hwnd, 0 );
8019
8020 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
8021 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8022 */
8023 SetRectEmpty( &rect );
8024 if (ValidateRect(0, &rect) && /* not supported on Win9x */
8025 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
8026 {
8027 check_update_rgn( hwnd, hrgn );
8028 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8029 flush_events();
8030 ok_sequence( WmPaint, "Paint", FALSE );
8031 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8032 check_update_rgn( hwnd, 0 );
8033 }
8034
8035 SetLastError(0xdeadbeef);
8036 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
8037 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
8038 "wrong error code %d\n", GetLastError());
8039 check_update_rgn( hwnd, 0 );
8040 flush_events();
8041 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8042
8043 SetLastError(0xdeadbeef);
8044 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
8045 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8046 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8047 "wrong error code %d\n", GetLastError());
8048 check_update_rgn( hwnd, 0 );
8049 flush_events();
8050 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8051
8052 SetLastError(0xdeadbeef);
8053 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
8054 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8055 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8056 "wrong error code %d\n", GetLastError());
8057 check_update_rgn( hwnd, 0 );
8058 flush_events();
8059 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8060
8061 /* now with frame */
8062 SetRectRgn( hrgn, -5, -5, 20, 20 );
8063
8064 /* flush pending messages */
8065 flush_events();
8066 flush_sequence();
8067 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8068 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8069
8070 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
8071 check_update_rgn( hwnd, hrgn );
8072
8073 flush_sequence();
8074 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8075 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8076
8077 flush_sequence();
8078 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8079 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
8080
8081 GetClientRect( hwnd, &rect );
8082 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8083 check_update_rgn( hwnd, hrgn );
8084
8085 flush_sequence();
8086 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
8087 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8088
8089 flush_sequence();
8090 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
8091 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
8092 check_update_rgn( hwnd, 0 );
8093
8094 flush_sequence();
8095 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
8096 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
8097 check_update_rgn( hwnd, 0 );
8098
8099 flush_sequence();
8100 SetRectRgn( hrgn, 0, 0, 100, 100 );
8101 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8102 SetRectRgn( hrgn, 0, 0, 50, 100 );
8103 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
8104 SetRectRgn( hrgn, 50, 0, 100, 100 );
8105 check_update_rgn( hwnd, hrgn );
8106 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8107 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
8108 check_update_rgn( hwnd, 0 );
8109
8110 flush_sequence();
8111 SetRectRgn( hrgn, 0, 0, 100, 100 );
8112 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8113 SetRectRgn( hrgn, 0, 0, 100, 50 );
8114 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8115 ok_sequence( WmErase, "Erase", FALSE );
8116 SetRectRgn( hrgn, 0, 50, 100, 100 );
8117 check_update_rgn( hwnd, hrgn );
8118
8119 flush_sequence();
8120 SetRectRgn( hrgn, 0, 0, 100, 100 );
8121 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8122 SetRectRgn( hrgn, 0, 0, 50, 50 );
8123 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
8124 ok_sequence( WmPaint, "Paint", FALSE );
8125
8126 flush_sequence();
8127 SetRectRgn( hrgn, -4, -4, -2, -2 );
8128 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8129 SetRectRgn( hrgn, -200, -200, -198, -198 );
8130 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
8131 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8132
8133 flush_sequence();
8134 SetRectRgn( hrgn, -4, -4, -2, -2 );
8135 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8136 SetRectRgn( hrgn, -4, -4, -3, -3 );
8137 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
8138 SetRectRgn( hrgn, 0, 0, 1, 1 );
8139 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
8140 ok_sequence( WmPaint, "Paint", FALSE );
8141
8142 flush_sequence();
8143 SetRectRgn( hrgn, -4, -4, -1, -1 );
8144 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8145 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
8146 /* make sure no WM_PAINT was generated */
8147 flush_events();
8148 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8149
8150 flush_sequence();
8151 SetRectRgn( hrgn, -4, -4, -1, -1 );
8152 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8153 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
8154 {
8155 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
8156 {
8157 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
8158 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
8159 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
8160 ret = GetUpdateRect( hwnd, &rect, FALSE );
8161 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
8162 /* this will send WM_NCPAINT and validate the non client area */
8163 ret = GetUpdateRect( hwnd, &rect, TRUE );
8164 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
8165 }
8166 DispatchMessageA( &msg );
8167 }
8168 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8169
8170 DestroyWindow( hwnd );
8171
8172 /* now test with a child window */
8173
8174 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8175 100, 100, 200, 200, 0, 0, 0, NULL);
8176 ok (hparent != 0, "Failed to create parent window\n");
8177
8178 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8179 10, 10, 100, 100, hparent, 0, 0, NULL);
8180 ok (hchild != 0, "Failed to create child window\n");
8181
8182 ShowWindow( hparent, SW_SHOW );
8183 UpdateWindow( hparent );
8184 UpdateWindow( hchild );
8185 flush_events();
8186 flush_sequence();
8187 log_all_parent_messages++;
8188
8189 SetRect( &rect, 0, 0, 50, 50 );
8190 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8191 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8192 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8193
8194 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8195 pt.x = pt.y = 0;
8196 MapWindowPoints( hchild, hparent, &pt, 1 );
8197 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8198 check_update_rgn( hchild, hrgn );
8199 SetRectRgn( hrgn, 0, 0, 50, 50 );
8200 check_update_rgn( hparent, hrgn );
8201 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8202 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8203 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8204 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8205
8206 flush_events();
8207 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8208
8209 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8210 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8211 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8212 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8213 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8214
8215 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8216 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8217 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8218
8219 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8220 flush_sequence();
8221 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8222 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8223 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8224
8225 /* flush all paint messages */
8226 flush_events();
8227 flush_sequence();
8228
8229 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8230 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8231 SetRectRgn( hrgn, 0, 0, 50, 50 );
8232 check_update_rgn( hparent, hrgn );
8233 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8234 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8235 SetRectRgn( hrgn, 0, 0, 50, 50 );
8236 check_update_rgn( hparent, hrgn );
8237
8238 /* flush all paint messages */
8239 flush_events();
8240 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8241 flush_sequence();
8242
8243 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8244 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8245 SetRectRgn( hrgn, 0, 0, 50, 50 );
8246 check_update_rgn( hparent, hrgn );
8247 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8248 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8249 SetRectRgn( hrgn2, 10, 10, 50, 50 );
8250 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8251 check_update_rgn( hparent, hrgn );
8252 /* flush all paint messages */
8253 flush_events();
8254 flush_sequence();
8255
8256 /* same as above but parent gets completely validated */
8257 SetRect( &rect, 20, 20, 30, 30 );
8258 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8259 SetRectRgn( hrgn, 20, 20, 30, 30 );
8260 check_update_rgn( hparent, hrgn );
8261 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8262 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8263 check_update_rgn( hparent, 0 ); /* no update region */
8264 flush_events();
8265 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
8266
8267 /* make sure RDW_VALIDATE on child doesn't have the same effect */
8268 flush_sequence();
8269 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8270 SetRectRgn( hrgn, 20, 20, 30, 30 );
8271 check_update_rgn( hparent, hrgn );
8272 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8273 SetRectRgn( hrgn, 20, 20, 30, 30 );
8274 check_update_rgn( hparent, hrgn );
8275
8276 /* same as above but normal WM_PAINT doesn't validate parent */
8277 flush_sequence();
8278 SetRect( &rect, 20, 20, 30, 30 );
8279 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8280 SetRectRgn( hrgn, 20, 20, 30, 30 );
8281 check_update_rgn( hparent, hrgn );
8282 /* no WM_PAINT in child while parent still pending */
8283 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8284 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8285 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8286 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8287
8288 flush_sequence();
8289 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8290 /* no WM_PAINT in child while parent still pending */
8291 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8292 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8293 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8294 /* now that parent is valid child should get WM_PAINT */
8295 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8296 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8297 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8298 ok_sequence( WmEmptySeq, "No other message", FALSE );
8299
8300 /* same thing with WS_CLIPCHILDREN in parent */
8301 flush_sequence();
8302 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8303 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8304 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8305 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8306 ok_sequence( WmEmptySeq, "No message", FALSE );
8307 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8308 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8309
8310 flush_sequence();
8311 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8312 SetRectRgn( hrgn, 20, 20, 30, 30 );
8313 check_update_rgn( hparent, hrgn );
8314 /* no WM_PAINT in child while parent still pending */
8315 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8316 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8317 /* WM_PAINT in parent first */
8318 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8319 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8320
8321 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8322 flush_sequence();
8323 SetRect( &rect, 0, 0, 30, 30 );
8324 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8325 SetRectRgn( hrgn, 0, 0, 30, 30 );
8326 check_update_rgn( hparent, hrgn );
8327 flush_events();
8328 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8329
8330 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8331 flush_sequence();
8332 SetRect( &rect, -10, 0, 30, 30 );
8333 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8334 SetRect( &rect, 0, 0, 20, 20 );
8335 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8336 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8337 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8338
8339 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8340 flush_sequence();
8341 SetRect( &rect, -10, 0, 30, 30 );
8342 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8343 SetRect( &rect, 0, 0, 100, 100 );
8344 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8345 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8346 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8347 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8348 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8349
8350 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8351 flush_sequence();
8352 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8353 GetClientRect( hparent, &rect );
8354 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8355 check_update_rgn( hparent, hrgn );
8356 flush_events();
8357
8358 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8359 GetClientRect( hparent, &rect );
8360 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8361 check_update_rgn( hparent, hrgn );
8362 flush_events();
8363
8364 /* test RDW_INTERNALPAINT behavior */
8365
8366 flush_sequence();
8367 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8368 flush_events();
8369 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8370
8371 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8372 flush_events();
8373 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8374
8375 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8376 flush_events();
8377 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8378
8379 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8380 UpdateWindow( hparent );
8381 flush_events();
8382 flush_sequence();
8383 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8384 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8385 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8386 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8387 flush_events();
8388 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8389
8390 UpdateWindow( hparent );
8391 flush_events();
8392 flush_sequence();
8393 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8394 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8395 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8396 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8397 flush_events();
8398 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8399
8400 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8401 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8402 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8403 flush_events();
8404 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8405
8406 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8407 UpdateWindow( hparent );
8408 flush_events();
8409 flush_sequence();
8410 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8411 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8412 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8413 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8414 flush_events();
8415 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8416
8417 UpdateWindow( hparent );
8418 flush_events();
8419 flush_sequence();
8420 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8421 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8422 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8423 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8424 flush_events();
8425 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8426
8427 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8428 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8429
8430 UpdateWindow( hparent );
8431 flush_events();
8432 flush_sequence();
8433 trace("testing SetWindowPos(-10000, -10000) on child\n");
8434 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8435 check_update_rgn( hchild, 0 );
8436 flush_events();
8437
8438 #if 0 /* this one doesn't pass under Wine yet */
8439 UpdateWindow( hparent );
8440 flush_events();
8441 flush_sequence();
8442 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8443 ShowWindow( hchild, SW_MINIMIZE );
8444 check_update_rgn( hchild, 0 );
8445 flush_events();
8446 #endif
8447
8448 UpdateWindow( hparent );
8449 flush_events();
8450 flush_sequence();
8451 trace("testing SetWindowPos(-10000, -10000) on parent\n");
8452 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8453 check_update_rgn( hparent, 0 );
8454 flush_events();
8455
8456 log_all_parent_messages--;
8457 DestroyWindow( hparent );
8458 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8459
8460 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8461
8462 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8463 100, 100, 200, 200, 0, 0, 0, NULL);
8464 ok (hparent != 0, "Failed to create parent window\n");
8465
8466 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8467 10, 10, 100, 100, hparent, 0, 0, NULL);
8468 ok (hchild != 0, "Failed to create child window\n");
8469
8470 ShowWindow( hparent, SW_SHOW );
8471 UpdateWindow( hparent );
8472 UpdateWindow( hchild );
8473 flush_events();
8474 flush_sequence();
8475
8476 /* moving child outside of parent boundaries changes update region */
8477 SetRect( &rect, 0, 0, 40, 40 );
8478 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8479 SetRectRgn( hrgn, 0, 0, 40, 40 );
8480 check_update_rgn( hchild, hrgn );
8481 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8482 SetRectRgn( hrgn, 10, 0, 40, 40 );
8483 check_update_rgn( hchild, hrgn );
8484 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8485 SetRectRgn( hrgn, 10, 10, 40, 40 );
8486 check_update_rgn( hchild, hrgn );
8487
8488 /* moving parent off-screen does too */
8489 SetRect( &rect, 0, 0, 100, 100 );
8490 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8491 SetRectRgn( hrgn, 0, 0, 100, 100 );
8492 check_update_rgn( hparent, hrgn );
8493 SetRectRgn( hrgn, 10, 10, 40, 40 );
8494 check_update_rgn( hchild, hrgn );
8495 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8496 GetUpdateRect( hparent, &rect2, FALSE );
8497 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8498 {
8499 rect.left += 20;
8500 rect.top += 20;
8501 }
8502 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8503 check_update_rgn( hparent, hrgn );
8504 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8505 check_update_rgn( hchild, hrgn );
8506
8507 /* invalidated region is cropped by the parent rects */
8508 SetRect( &rect, 0, 0, 50, 50 );
8509 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8510 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8511 check_update_rgn( hchild, hrgn );
8512
8513 DestroyWindow( hparent );
8514 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8515 flush_sequence();
8516
8517 DeleteObject( hrgn );
8518 DeleteObject( hrgn2 );
8519 }
8520
8521 struct wnd_event
8522 {
8523 HWND hwnd;
8524 HANDLE grand_child;
8525 HANDLE start_event;
8526 HANDLE stop_event;
8527 };
8528
8529 static DWORD WINAPI thread_proc(void *param)
8530 {
8531 MSG msg;
8532 struct wnd_event *wnd_event = param;
8533
8534 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8535 100, 100, 200, 200, 0, 0, 0, NULL);
8536 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8537
8538 SetEvent(wnd_event->start_event);
8539
8540 while (GetMessageA(&msg, 0, 0, 0))
8541 {
8542 TranslateMessage(&msg);
8543 DispatchMessageA(&msg);
8544 }
8545
8546 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8547
8548 return 0;
8549 }
8550
8551 static DWORD CALLBACK create_grand_child_thread( void *param )
8552 {
8553 struct wnd_event *wnd_event = param;
8554 HWND hchild;
8555 MSG msg;
8556
8557 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8558 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8559 ok (hchild != 0, "Failed to create child window\n");
8560 flush_events();
8561 flush_sequence();
8562 SetEvent( wnd_event->start_event );
8563
8564 for (;;)
8565 {
8566 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8567 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
8568 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8569 }
8570 return 0;
8571 }
8572
8573 static DWORD CALLBACK create_child_thread( void *param )
8574 {
8575 struct wnd_event *wnd_event = param;
8576 struct wnd_event child_event;
8577 DWORD ret, tid;
8578 MSG msg;
8579
8580 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8581 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8582 ok (child_event.hwnd != 0, "Failed to create child window\n");
8583 SetFocus( child_event.hwnd );
8584 flush_events();
8585 flush_sequence();
8586 child_event.start_event = wnd_event->start_event;
8587 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8588 for (;;)
8589 {
8590 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8591 if (ret != 1) break;
8592 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8593 }
8594 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8595 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8596 return 0;
8597 }
8598
8599 static const char manifest_dep[] =
8600 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8601 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8602 " <file name=\"testdep.dll\" />"
8603 "</assembly>";
8604
8605 static const char manifest_main[] =
8606 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8607 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8608 "<dependency>"
8609 " <dependentAssembly>"
8610 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8611 " </dependentAssembly>"
8612 "</dependency>"
8613 "</assembly>";
8614
8615 static void create_manifest_file(const char *filename, const char *manifest)
8616 {
8617 WCHAR path[MAX_PATH];
8618 HANDLE file;
8619 DWORD size;
8620
8621 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8622 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8623 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8624 WriteFile(file, manifest, strlen(manifest), &size, NULL);
8625 CloseHandle(file);
8626 }
8627
8628 static HANDLE test_create(const char *file)
8629 {
8630 WCHAR path[MAX_PATH];
8631 ACTCTXW actctx;
8632 HANDLE handle;
8633
8634 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8635 memset(&actctx, 0, sizeof(ACTCTXW));
8636 actctx.cbSize = sizeof(ACTCTXW);
8637 actctx.lpSource = path;
8638
8639 handle = pCreateActCtxW(&actctx);
8640 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8641
8642 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8643 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8644 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8645 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8646 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8647 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8648 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8649 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8650 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8651
8652 return handle;
8653 }
8654
8655 static void test_interthread_messages(void)
8656 {
8657 HANDLE hThread, context, handle, event;
8658 ULONG_PTR cookie;
8659 DWORD tid;
8660 WNDPROC proc;
8661 MSG msg;
8662 char buf[256];
8663 int len, expected_len;
8664 struct wnd_event wnd_event;
8665 BOOL ret;
8666
8667 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8668 if (!wnd_event.start_event)
8669 {
8670 win_skip("skipping interthread message test under win9x\n");
8671 return;
8672 }
8673
8674 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8675 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8676
8677 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8678
8679 CloseHandle(wnd_event.start_event);
8680
8681 SetLastError(0xdeadbeef);
8682 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8683 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8684 "wrong error code %d\n", GetLastError());
8685
8686 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8687 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8688
8689 expected_len = lstrlenA("window caption text");
8690 memset(buf, 0, sizeof(buf));
8691 SetLastError(0xdeadbeef);
8692 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8693 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8694 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8695
8696 msg.hwnd = wnd_event.hwnd;
8697 msg.message = WM_GETTEXT;
8698 msg.wParam = sizeof(buf);
8699 msg.lParam = (LPARAM)buf;
8700 memset(buf, 0, sizeof(buf));
8701 SetLastError(0xdeadbeef);
8702 len = DispatchMessageA(&msg);
8703 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8704 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8705
8706 /* the following test causes an exception in user.exe under win9x */
8707 msg.hwnd = wnd_event.hwnd;
8708 msg.message = WM_TIMER;
8709 msg.wParam = 0;
8710 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8711 SetLastError(0xdeadbeef);
8712 len = DispatchMessageA(&msg);
8713 ok(!len && GetLastError() == 0xdeadbeef,
8714 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8715
8716 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8717 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8718
8719 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8720 CloseHandle(hThread);
8721
8722 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8723
8724 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8725 100, 100, 200, 200, 0, 0, 0, NULL);
8726 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8727 flush_events();
8728 flush_sequence();
8729 log_all_parent_messages++;
8730 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8731 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8732 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
8733 for (;;)
8734 {
8735 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8736 if (ret != 1) break;
8737 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8738 }
8739 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
8740 /* now wait for the thread without processing messages; this shouldn't deadlock */
8741 SetEvent( wnd_event.stop_event );
8742 ret = WaitForSingleObject( hThread, 5000 );
8743 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8744 CloseHandle( hThread );
8745
8746 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8747 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8748 CloseHandle( wnd_event.grand_child );
8749
8750 CloseHandle( wnd_event.start_event );
8751 CloseHandle( wnd_event.stop_event );
8752 flush_events();
8753 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8754 log_all_parent_messages--;
8755 DestroyWindow( wnd_event.hwnd );
8756
8757 /* activation context tests */
8758 if (!pActivateActCtx)
8759 {
8760 win_skip("Activation contexts are not supported, skipping\n");
8761 return;
8762 }
8763
8764 create_manifest_file("testdep1.manifest", manifest_dep);
8765 create_manifest_file("main.manifest", manifest_main);
8766
8767 context = test_create("main.manifest");
8768 DeleteFileA("testdep1.manifest");
8769 DeleteFileA("main.manifest");
8770
8771 handle = (void*)0xdeadbeef;
8772 ret = pGetCurrentActCtx(&handle);
8773 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8774 ok(handle == 0, "active context %p\n", handle);
8775
8776 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8777 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8778 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8779 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8780 CloseHandle(wnd_event.start_event);
8781
8782 /* context is activated after thread creation, so it doesn't inherit it by default */
8783 ret = pActivateActCtx(context, &cookie);
8784 ok(ret, "activation failed: %u\n", GetLastError());
8785
8786 handle = 0;
8787 ret = pGetCurrentActCtx(&handle);
8788 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8789 ok(handle != 0, "active context %p\n", handle);
8790 pReleaseActCtx(handle);
8791
8792 /* destination window will test for active context */
8793 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8794 ok(ret, "thread window returned %d\n", ret);
8795
8796 event = CreateEventW(NULL, 0, 0, NULL);
8797 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8798 ok(ret, "thread window returned %d\n", ret);
8799 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8800 CloseHandle(event);
8801
8802 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8803 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8804
8805 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8806 CloseHandle(hThread);
8807
8808 ret = pDeactivateActCtx(0, cookie);
8809 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8810 pReleaseActCtx(context);
8811 }
8812
8813
8814 static const struct message WmVkN[] = {
8815 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8816 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8817 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8818 { WM_CHAR, wparam|lparam, 'n', 1 },
8819 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8820 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8821 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8822 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8823 { 0 }
8824 };
8825 static const struct message WmShiftVkN[] = {
8826 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8827 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8828 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8829 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8830 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8831 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8832 { WM_CHAR, wparam|lparam, 'N', 1 },
8833 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8834 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8835 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8836 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8837 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8838 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8839 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8840 { 0 }
8841 };
8842 static const struct message WmCtrlVkN[] = {
8843 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8844 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8845 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8846 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8847 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8848 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8849 { WM_CHAR, wparam|lparam, 0x000e, 1 },
8850 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8851 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8852 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8853 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8854 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8855 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8856 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8857 { 0 }
8858 };
8859 static const struct message WmCtrlVkN_2[] = {
8860 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8861 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8862 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8863 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8864 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8865 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8866 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8867 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8868 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8869 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8870 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8871 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8872 { 0 }
8873 };
8874 static const struct message WmAltVkN[] = {
8875 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8876 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8877 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8878 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8879 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8880 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8881 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8882 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8883 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8884 { HCBT_SYSCOMMAND, hook },
8885 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8886 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8887 { 0x00AE, sent|defwinproc|optional }, /* XP */
8888 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8889 { WM_INITMENU, sent|defwinproc },
8890 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8891 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8892 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8893 { WM_CAPTURECHANGED, sent|defwinproc },
8894 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8895 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8896 { WM_EXITMENULOOP, sent|defwinproc },
8897 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8898 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8899 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8900 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8901 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8902 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8903 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8904 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8905 { 0 }
8906 };
8907 static const struct message WmAltVkN_2[] = {
8908 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8909 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8910 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8911 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8912 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8913 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8914 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8915 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8916 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8917 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8918 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8919 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8920 { 0 }
8921 };
8922 static const struct message WmCtrlAltVkN[] = {
8923 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8924 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8925 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8926 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8927 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8928 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8929 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8930 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8931 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8932 { WM_CHAR, optional },
8933 { WM_CHAR, sent|optional },
8934 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8935 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8936 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8937 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8938 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8939 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8940 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8941 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8942 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8943 { 0 }
8944 };
8945 static const struct message WmCtrlShiftVkN[] = {
8946 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8947 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8948 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8949 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8950 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8951 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8952 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8953 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8954 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8955 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8956 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8957 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8958 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8959 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8960 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8961 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8962 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8963 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8964 { 0 }
8965 };
8966 static const struct message WmCtrlAltShiftVkN[] = {
8967 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8968 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8969 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8970 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8971 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8972 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8973 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8974 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8975 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8976 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8977 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8978 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8979 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8980 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8981 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8982 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8983 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8984 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8985 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8986 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8987 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8988 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8989 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8990 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8991 { 0 }
8992 };
8993 static const struct message WmAltPressRelease[] = {
8994 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8995 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8996 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8997 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8998 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8999 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9000 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
9001 { HCBT_SYSCOMMAND, hook },
9002 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9003 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9004 { WM_INITMENU, sent|defwinproc },
9005 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9006 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9007 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9008
9009 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
9010
9011 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9012 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9013 { WM_CAPTURECHANGED, sent|defwinproc },
9014 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9015 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9016 { WM_EXITMENULOOP, sent|defwinproc },
9017 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9018 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9019 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9020 { 0 }
9021 };
9022 static const struct message WmShiftMouseButton[] = {
9023 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9024 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9025 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9026 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
9027 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
9028 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
9029 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
9030 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
9031 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
9032 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9033 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9034 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9035 { 0 }
9036 };
9037 static const struct message WmF1Seq[] = {
9038 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
9039 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
9040 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
9041 { WM_KEYF1, wparam|lparam, 0, 0 },
9042 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
9043 { WM_HELP, sent|defwinproc },
9044 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
9045 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
9046 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
9047 { 0 }
9048 };
9049 static const struct message WmVkAppsSeq[] = {
9050 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
9051 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
9052 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
9053 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
9054 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
9055 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
9056 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
9057 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
9058 { 0 }
9059 };
9060 static const struct message WmVkF10Seq[] = {
9061 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9062 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9063 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9064 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9065 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9066 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9067 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9068 { HCBT_SYSCOMMAND, hook },
9069 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9070 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9071 { WM_INITMENU, sent|defwinproc },
9072 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9073 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9074 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9075
9076 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
9077
9078 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9079 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9080 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9081 { WM_CAPTURECHANGED, sent|defwinproc },
9082 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9083 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9084 { WM_EXITMENULOOP, sent|defwinproc },
9085 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9086 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9087 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9088 { 0 }
9089 };
9090 static const struct message WmShiftF10Seq[] = {
9091 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9092 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9093 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
9094 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9095 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9096 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9097 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
9098 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9099 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9100 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9101 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9102 { HCBT_SYSCOMMAND, hook },
9103 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9104 { WM_INITMENU, sent|defwinproc },
9105 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9106 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
9107 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
9108 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
9109 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
9110 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9111 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
9112 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
9113 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
9114 { 0 }
9115 };
9116
9117 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
9118 {
9119 MSG msg;
9120
9121 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
9122 {
9123 struct recvd_message log_msg;
9124
9125 /* ignore some unwanted messages */
9126 if (msg.message == WM_MOUSEMOVE ||
9127 msg.message == WM_TIMER ||
9128 ignore_message( msg.message ))
9129 continue;
9130
9131 log_msg.hwnd = msg.hwnd;
9132 log_msg.message = msg.message;
9133 log_msg.flags = wparam|lparam;
9134 log_msg.wParam = msg.wParam;
9135 log_msg.lParam = msg.lParam;
9136 log_msg.descr = "accel";
9137 add_message(&log_msg);
9138
9139 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
9140 {
9141 TranslateMessage(&msg);
9142 DispatchMessageA(&msg);
9143 }
9144 }
9145 }
9146
9147 static void test_accelerators(void)
9148 {
9149 RECT rc;
9150 POINT pt;
9151 SHORT state;
9152 HACCEL hAccel;
9153 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9154 100, 100, 200, 200, 0, 0, 0, NULL);
9155 BOOL ret;
9156
9157 assert(hwnd != 0);
9158 UpdateWindow(hwnd);
9159 flush_events();
9160 flush_sequence();
9161
9162 SetFocus(hwnd);
9163 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
9164
9165 state = GetKeyState(VK_SHIFT);
9166 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
9167 state = GetKeyState(VK_CAPITAL);
9168 ok(state == 0, "wrong CapsLock state %04x\n", state);
9169
9170 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
9171 assert(hAccel != 0);
9172
9173 flush_events();
9174 pump_msg_loop(hwnd, 0);
9175 flush_sequence();
9176
9177 trace("testing VK_N press/release\n");
9178 flush_sequence();
9179 keybd_event('N', 0, 0, 0);
9180 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9181 pump_msg_loop(hwnd, hAccel);
9182 if (!sequence_cnt) /* we didn't get any message */
9183 {
9184 skip( "queuing key events not supported\n" );
9185 goto done;
9186 }
9187 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9188
9189 trace("testing Shift+VK_N press/release\n");
9190 flush_sequence();
9191 keybd_event(VK_SHIFT, 0, 0, 0);
9192 keybd_event('N', 0, 0, 0);
9193 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9194 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9195 pump_msg_loop(hwnd, hAccel);
9196 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9197
9198 trace("testing Ctrl+VK_N press/release\n");
9199 flush_sequence();
9200 keybd_event(VK_CONTROL, 0, 0, 0);
9201 keybd_event('N', 0, 0, 0);
9202 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9203 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9204 pump_msg_loop(hwnd, hAccel);
9205 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
9206
9207 trace("testing Alt+VK_N press/release\n");
9208 flush_sequence();
9209 keybd_event(VK_MENU, 0, 0, 0);
9210 keybd_event('N', 0, 0, 0);
9211 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9212 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9213 pump_msg_loop(hwnd, hAccel);
9214 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
9215
9216 trace("testing Ctrl+Alt+VK_N press/release 1\n");
9217 flush_sequence();
9218 keybd_event(VK_CONTROL, 0, 0, 0);
9219 keybd_event(VK_MENU, 0, 0, 0);
9220 keybd_event('N', 0, 0, 0);
9221 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9222 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9223 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9224 pump_msg_loop(hwnd, hAccel);
9225 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
9226
9227 ret = DestroyAcceleratorTable(hAccel);
9228 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9229
9230 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
9231 assert(hAccel != 0);
9232
9233 trace("testing VK_N press/release\n");
9234 flush_sequence();
9235 keybd_event('N', 0, 0, 0);
9236 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9237 pump_msg_loop(hwnd, hAccel);
9238 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9239
9240 trace("testing Shift+VK_N press/release\n");
9241 flush_sequence();
9242 keybd_event(VK_SHIFT, 0, 0, 0);
9243 keybd_event('N', 0, 0, 0);
9244 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9245 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9246 pump_msg_loop(hwnd, hAccel);
9247 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9248
9249 trace("testing Ctrl+VK_N press/release 2\n");
9250 flush_sequence();
9251 keybd_event(VK_CONTROL, 0, 0, 0);
9252 keybd_event('N', 0, 0, 0);
9253 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9254 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9255 pump_msg_loop(hwnd, hAccel);
9256 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
9257
9258 trace("testing Alt+VK_N press/release 2\n");
9259 flush_sequence();
9260 keybd_event(VK_MENU, 0, 0, 0);
9261 keybd_event('N', 0, 0, 0);
9262 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9263 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9264 pump_msg_loop(hwnd, hAccel);
9265 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
9266
9267 trace("testing Ctrl+Alt+VK_N press/release 2\n");
9268 flush_sequence();
9269 keybd_event(VK_CONTROL, 0, 0, 0);
9270 keybd_event(VK_MENU, 0, 0, 0);
9271 keybd_event('N', 0, 0, 0);
9272 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9273 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9274 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9275 pump_msg_loop(hwnd, hAccel);
9276 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9277
9278 trace("testing Ctrl+Shift+VK_N press/release\n");
9279 flush_sequence();
9280 keybd_event(VK_CONTROL, 0, 0, 0);
9281 keybd_event(VK_SHIFT, 0, 0, 0);
9282 keybd_event('N', 0, 0, 0);
9283 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9284 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9285 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9286 pump_msg_loop(hwnd, hAccel);
9287 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9288
9289 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9290 flush_sequence();
9291 keybd_event(VK_CONTROL, 0, 0, 0);
9292 keybd_event(VK_MENU, 0, 0, 0);
9293 keybd_event(VK_SHIFT, 0, 0, 0);
9294 keybd_event('N', 0, 0, 0);
9295 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9296 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9297 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9298 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9299 pump_msg_loop(hwnd, hAccel);
9300 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9301
9302 ret = DestroyAcceleratorTable(hAccel);
9303 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9304 hAccel = 0;
9305
9306 trace("testing Alt press/release\n");
9307 flush_sequence();
9308 keybd_event(VK_MENU, 0, 0, 0);
9309 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9310 keybd_event(VK_MENU, 0, 0, 0);
9311 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9312 pump_msg_loop(hwnd, 0);
9313 /* this test doesn't pass in Wine for managed windows */
9314 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
9315
9316 trace("testing VK_F1 press/release\n");
9317 keybd_event(VK_F1, 0, 0, 0);
9318 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9319 pump_msg_loop(hwnd, 0);
9320 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9321
9322 trace("testing VK_APPS press/release\n");
9323 keybd_event(VK_APPS, 0, 0, 0);
9324 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9325 pump_msg_loop(hwnd, 0);
9326 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9327
9328 trace("testing VK_F10 press/release\n");
9329 keybd_event(VK_F10, 0, 0, 0);
9330 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9331 keybd_event(VK_F10, 0, 0, 0);
9332 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9333 pump_msg_loop(hwnd, 0);
9334 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
9335
9336 trace("testing SHIFT+F10 press/release\n");
9337 keybd_event(VK_SHIFT, 0, 0, 0);
9338 keybd_event(VK_F10, 0, 0, 0);
9339 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9340 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9341 keybd_event(VK_ESCAPE, 0, 0, 0);
9342 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9343 pump_msg_loop(hwnd, 0);
9344 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9345
9346 trace("testing Shift+MouseButton press/release\n");
9347 /* first, move mouse pointer inside of the window client area */
9348 GetClientRect(hwnd, &rc);
9349 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9350 rc.left += (rc.right - rc.left)/2;
9351 rc.top += (rc.bottom - rc.top)/2;
9352 SetCursorPos(rc.left, rc.top);
9353 SetActiveWindow(hwnd);
9354
9355 flush_events();
9356 flush_sequence();
9357 GetCursorPos(&pt);
9358 if (pt.x == rc.left && pt.y == rc.top)
9359 {
9360 int i;
9361 keybd_event(VK_SHIFT, 0, 0, 0);
9362 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9363 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9364 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9365 pump_msg_loop(hwnd, 0);
9366 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9367 if (i < sequence_cnt)
9368 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9369 else
9370 skip( "Shift+MouseButton event didn't get to the window\n" );
9371 }
9372
9373 done:
9374 if (hAccel) DestroyAcceleratorTable(hAccel);
9375 DestroyWindow(hwnd);
9376 }
9377
9378 /************* window procedures ********************/
9379
9380 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9381 WPARAM wParam, LPARAM lParam)
9382 {
9383 static LONG defwndproc_counter = 0;
9384 static LONG beginpaint_counter = 0;
9385 LRESULT ret;
9386 struct recvd_message msg;
9387
9388 if (ignore_message( message )) return 0;
9389
9390 switch (message)
9391 {
9392 case WM_ENABLE:
9393 {
9394 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9395 ok((BOOL)wParam == !(style & WS_DISABLED),
9396 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9397 break;
9398 }
9399
9400 case WM_CAPTURECHANGED:
9401 if (test_DestroyWindow_flag)
9402 {
9403 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9404 if (style & WS_CHILD)
9405 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9406 else if (style & WS_POPUP)
9407 lParam = WND_POPUP_ID;
9408 else
9409 lParam = WND_PARENT_ID;
9410 }
9411 break;
9412
9413 case WM_NCDESTROY:
9414 {
9415 HWND capture;
9416
9417 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9418 capture = GetCapture();
9419 if (capture)
9420 {
9421 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9422 trace("current capture %p, releasing...\n", capture);
9423 ReleaseCapture();
9424 }
9425 }
9426 /* fall through */
9427 case WM_DESTROY:
9428 if (pGetAncestor)
9429 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9430 if (test_DestroyWindow_flag)
9431 {
9432 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9433 if (style & WS_CHILD)
9434 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9435 else if (style & WS_POPUP)
9436 lParam = WND_POPUP_ID;
9437 else
9438 lParam = WND_PARENT_ID;
9439 }
9440 break;
9441
9442 /* test_accelerators() depends on this */
9443 case WM_NCHITTEST:
9444 return HTCLIENT;
9445
9446 case WM_USER+10:
9447 {
9448 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9449 HANDLE handle, event = (HANDLE)lParam;
9450 BOOL ret;
9451
9452 handle = (void*)0xdeadbeef;
9453 ret = pGetCurrentActCtx(&handle);
9454 ok(ret, "failed to get current context, %u\n", GetLastError());
9455 ok(handle == 0, "got active context %p\n", handle);
9456
9457 memset(&basicinfo, 0xff, sizeof(basicinfo));
9458 ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9459 &basicinfo, sizeof(basicinfo), NULL);
9460 ok(ret, "got %d, error %d\n", ret, GetLastError());
9461 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9462 ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9463
9464 if (event) SetEvent(event);
9465 return 1;
9466 }
9467
9468 /* ignore */
9469 case WM_MOUSEMOVE:
9470 case WM_MOUSEACTIVATE:
9471 case WM_NCMOUSEMOVE:
9472 case WM_SETCURSOR:
9473 case WM_IME_SELECT:
9474 return 0;
9475 }
9476
9477 msg.hwnd = hwnd;
9478 msg.message = message;
9479 msg.flags = sent|wparam|lparam;
9480 if (defwndproc_counter) msg.flags |= defwinproc;
9481 if (beginpaint_counter) msg.flags |= beginpaint;
9482 msg.wParam = wParam;
9483 msg.lParam = lParam;
9484 msg.descr = "MsgCheckProc";
9485 add_message(&msg);
9486
9487 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9488 {
9489 HWND parent = GetParent(hwnd);
9490 RECT rc;
9491 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9492
9493 GetClientRect(parent, &rc);
9494 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9495 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9496 minmax->ptReserved.x, minmax->ptReserved.y,
9497 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9498 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9499 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9500 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9501
9502 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9503 minmax->ptMaxSize.x, rc.right);
9504 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9505 minmax->ptMaxSize.y, rc.bottom);
9506 }
9507
9508 if (message == WM_PAINT)
9509 {
9510 PAINTSTRUCT ps;
9511 beginpaint_counter++;
9512 BeginPaint( hwnd, &ps );
9513 beginpaint_counter--;
9514 EndPaint( hwnd, &ps );
9515 return 0;
9516 }
9517
9518 if (!test_context_menu && message == WM_CONTEXTMENU)
9519 {
9520 /* don't create context menu */
9521 return 0;
9522 }
9523
9524 defwndproc_counter++;
9525 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9526 : DefWindowProcA(hwnd, message, wParam, lParam);
9527 defwndproc_counter--;
9528
9529 return ret;
9530 }
9531
9532 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9533 {
9534 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9535 }
9536
9537 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9538 {
9539 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9540 }
9541
9542 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9543 {
9544 static LONG defwndproc_counter = 0;
9545 LRESULT ret;
9546 struct recvd_message msg;
9547
9548 if (ignore_message( message )) return 0;
9549
9550 switch (message)
9551 {
9552 case WM_QUERYENDSESSION:
9553 case WM_ENDSESSION:
9554 lParam &= ~0x01; /* Vista adds a 0x01 flag */
9555 break;
9556 }
9557
9558 msg.hwnd = hwnd;
9559 msg.message = message;
9560 msg.flags = sent|wparam|lparam;
9561 if (defwndproc_counter) msg.flags |= defwinproc;
9562 msg.wParam = wParam;
9563 msg.lParam = lParam;
9564 msg.descr = "popup";
9565 add_message(&msg);
9566
9567 if (message == WM_CREATE)
9568 {
9569 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9570 SetWindowLongA(hwnd, GWL_STYLE, style);
9571 }
9572
9573 defwndproc_counter++;
9574 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9575 defwndproc_counter--;
9576
9577 return ret;
9578 }
9579
9580 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9581 {
9582 static LONG defwndproc_counter = 0;
9583 static LONG beginpaint_counter = 0;
9584 LRESULT ret;
9585 struct recvd_message msg;
9586
9587 if (ignore_message( message )) return 0;
9588
9589 if (log_all_parent_messages ||
9590 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9591 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9592 message == WM_ENABLE || message == WM_ENTERIDLE ||
9593 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9594 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9595 {
9596 switch (message)
9597 {
9598 /* ignore */
9599 case WM_NCHITTEST:
9600 return HTCLIENT;
9601 case WM_SETCURSOR:
9602 case WM_MOUSEMOVE:
9603 case WM_NCMOUSEMOVE:
9604 return 0;
9605
9606 case WM_ERASEBKGND:
9607 {
9608 RECT rc;
9609 INT ret = GetClipBox((HDC)wParam, &rc);
9610
9611 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9612 break;
9613 }
9614 }
9615
9616 msg.hwnd = hwnd;
9617 msg.message = message;
9618 msg.flags = sent|parent|wparam|lparam;
9619 if (defwndproc_counter) msg.flags |= defwinproc;
9620 if (beginpaint_counter) msg.flags |= beginpaint;
9621 msg.wParam = wParam;
9622 msg.lParam = lParam;
9623 msg.descr = "parent";
9624 add_message(&msg);
9625 }
9626
9627 if (message == WM_PAINT)
9628 {
9629 PAINTSTRUCT ps;
9630 beginpaint_counter++;
9631 BeginPaint( hwnd, &ps );
9632 beginpaint_counter--;
9633 EndPaint( hwnd, &ps );
9634 return 0;
9635 }
9636
9637 defwndproc_counter++;
9638 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9639 defwndproc_counter--;
9640
9641 return message == WM_COMPAREITEM ? -1 : ret;
9642 }
9643
9644 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9645 {
9646 if (message == WM_CREATE)
9647 PostMessageA(hwnd, WM_CLOSE, 0, 0);
9648 else if (message == WM_CLOSE)
9649 {
9650 /* Only the first WM_QUIT will survive the window destruction */
9651 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9652 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9653 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9654 }
9655
9656 return DefWindowProcA(hwnd, message, wp, lp);
9657 }
9658
9659 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9660 {
9661 static LONG defwndproc_counter = 0;
9662 LRESULT ret;
9663 struct recvd_message msg;
9664
9665 if (ignore_message( message )) return 0;
9666
9667 if (test_def_id)
9668 {
9669 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9670 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9671 if (after_end_dialog)
9672 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9673 else
9674 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9675 }
9676
9677 msg.hwnd = hwnd;
9678 msg.message = message;
9679 msg.flags = sent|wparam|lparam;
9680 if (defwndproc_counter) msg.flags |= defwinproc;
9681 msg.wParam = wParam;
9682 msg.lParam = lParam;
9683 msg.descr = "dialog";
9684 add_message(&msg);
9685
9686 defwndproc_counter++;
9687 ret = DefDlgProcA(hwnd, message, wParam, lParam);
9688 defwndproc_counter--;
9689
9690 return ret;
9691 }
9692
9693 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9694 {
9695 static LONG defwndproc_counter = 0;
9696 LRESULT ret;
9697 struct recvd_message msg;
9698
9699 /* log only specific messages we are interested in */
9700 switch (message)
9701 {
9702 #if 0 /* probably log these as well */
9703 case WM_ACTIVATE:
9704 case WM_SETFOCUS:
9705 case WM_KILLFOCUS:
9706 #endif
9707 case WM_SHOWWINDOW:
9708 case WM_SIZE:
9709 case WM_MOVE:
9710 case WM_GETMINMAXINFO:
9711 case WM_WINDOWPOSCHANGING:
9712 case WM_WINDOWPOSCHANGED:
9713 break;
9714
9715 default: /* ignore */
9716 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9717 return DefWindowProcA(hwnd, message, wParam, lParam);
9718 }
9719
9720 msg.hwnd = hwnd;
9721 msg.message = message;
9722 msg.flags = sent|wparam|lparam;
9723 if (defwndproc_counter) msg.flags |= defwinproc;
9724 msg.wParam = wParam;
9725 msg.lParam = lParam;
9726 msg.descr = "show";
9727 add_message(&msg);
9728
9729 defwndproc_counter++;
9730 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9731 defwndproc_counter--;
9732
9733 return ret;
9734 }
9735
9736 static LRESULT WINAPI recursive_activation_wndprocA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9737 {
9738 static LONG defwndproc_counter = 0;
9739 struct recvd_message msg;
9740 LRESULT ret;
9741
9742 switch (message)
9743 {
9744 /* log only specific messages we are interested in */
9745 case WM_NCACTIVATE:
9746 case WM_ACTIVATE:
9747 case WM_SETFOCUS:
9748 case WM_KILLFOCUS:
9749 break;
9750 default:
9751 return DefWindowProcA(hwnd, message, wParam, lParam);
9752 }
9753
9754 msg.hwnd = hwnd;
9755 msg.message = message;
9756 msg.flags = sent|wparam|lparam;
9757 if (defwndproc_counter) msg.flags |= defwinproc;
9758 msg.wParam = wParam;
9759 msg.lParam = lParam;
9760 msg.descr = "recursive_activation";
9761 add_message(&msg);
9762
9763 /* recursively activate ourselves by first losing activation and changing it back */
9764 if (message == WM_ACTIVATE && LOWORD(wParam) != WA_INACTIVE)
9765 {
9766 SetActiveWindow((HWND)lParam);
9767 SetActiveWindow(hwnd);
9768 return 0;
9769 }
9770
9771 defwndproc_counter++;
9772 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9773 defwndproc_counter--;
9774
9775 return ret;
9776 }
9777
9778 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
9779 {
9780 switch (msg)
9781 {
9782 case WM_CREATE: return 0;
9783 case WM_PAINT:
9784 {
9785 MSG msg2;
9786 static int i = 0;
9787
9788 if (i < 256)
9789 {
9790 i++;
9791 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9792 {
9793 TranslateMessage(&msg2);
9794 DispatchMessageA(&msg2);
9795 }
9796 i--;
9797 }
9798 else ok(broken(1), "infinite loop\n");
9799 if ( i == 0)
9800 paint_loop_done = TRUE;
9801 return DefWindowProcA(hWnd,msg,wParam,lParam);
9802 }
9803 }
9804 return DefWindowProcA(hWnd,msg,wParam,lParam);
9805 }
9806
9807 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9808 {
9809 static LONG defwndproc_counter = 0;
9810 LRESULT ret;
9811 struct recvd_message msg;
9812 DWORD queue_status;
9813
9814 if (ignore_message( message )) return 0;
9815
9816 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9817 message == WM_HOTKEY || message >= WM_APP)
9818 {
9819 msg.hwnd = hwnd;
9820 msg.message = message;
9821 msg.flags = sent|wparam|lparam;
9822 if (defwndproc_counter) msg.flags |= defwinproc;
9823 msg.wParam = wParam;
9824 msg.lParam = lParam;
9825 msg.descr = "HotkeyMsgCheckProcA";
9826 add_message(&msg);
9827 }
9828
9829 defwndproc_counter++;
9830 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9831 defwndproc_counter--;
9832
9833 if (message == WM_APP)
9834 {
9835 queue_status = GetQueueStatus(QS_HOTKEY);
9836 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9837 queue_status = GetQueueStatus(QS_POSTMESSAGE);
9838 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9839 PostMessageA(hwnd, WM_APP+1, 0, 0);
9840 }
9841 else if (message == WM_APP+1)
9842 {
9843 queue_status = GetQueueStatus(QS_HOTKEY);
9844 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9845 }
9846
9847 return ret;
9848 }
9849
9850 static BOOL RegisterWindowClasses(void)
9851 {
9852 WNDCLASSA cls;
9853 WNDCLASSW clsW;
9854
9855 cls.style = 0;
9856 cls.lpfnWndProc = MsgCheckProcA;
9857 cls.cbClsExtra = 0;
9858 cls.cbWndExtra = 0;
9859 cls.hInstance = GetModuleHandleA(0);
9860 cls.hIcon = 0;
9861 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9862 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9863 cls.lpszMenuName = NULL;
9864 cls.lpszClassName = "TestWindowClass";
9865 if(!RegisterClassA(&cls)) return FALSE;
9866
9867 cls.lpfnWndProc = HotkeyMsgCheckProcA;
9868 cls.lpszClassName = "HotkeyWindowClass";
9869 if(!RegisterClassA(&cls)) return FALSE;
9870
9871 cls.lpfnWndProc = ShowWindowProcA;
9872 cls.lpszClassName = "ShowWindowClass";
9873 if(!RegisterClassA(&cls)) return FALSE;
9874
9875 cls.lpfnWndProc = recursive_activation_wndprocA;
9876 cls.lpszClassName = "RecursiveActivationClass";
9877 if(!RegisterClassA(&cls)) return FALSE;
9878
9879 cls.lpfnWndProc = PopupMsgCheckProcA;
9880 cls.lpszClassName = "TestPopupClass";
9881 if(!RegisterClassA(&cls)) return FALSE;
9882
9883 cls.lpfnWndProc = ParentMsgCheckProcA;
9884 cls.lpszClassName = "TestParentClass";
9885 if(!RegisterClassA(&cls)) return FALSE;
9886
9887 cls.lpfnWndProc = StopQuitMsgCheckProcA;
9888 cls.lpszClassName = "StopQuitClass";
9889 if(!RegisterClassA(&cls)) return FALSE;
9890
9891 cls.lpfnWndProc = DefWindowProcA;
9892 cls.lpszClassName = "SimpleWindowClass";
9893 if(!RegisterClassA(&cls)) return FALSE;
9894
9895 cls.lpfnWndProc = PaintLoopProcA;
9896 cls.lpszClassName = "PaintLoopWindowClass";
9897 if(!RegisterClassA(&cls)) return FALSE;
9898
9899 cls.style = CS_NOCLOSE;
9900 cls.lpszClassName = "NoCloseWindowClass";
9901 if(!RegisterClassA(&cls)) return FALSE;
9902
9903 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9904 cls.style = 0;
9905 cls.hInstance = GetModuleHandleA(0);
9906 cls.hbrBackground = 0;
9907 cls.lpfnWndProc = TestDlgProcA;
9908 cls.lpszClassName = "TestDialogClass";
9909 if(!RegisterClassA(&cls)) return FALSE;
9910
9911 clsW.style = 0;
9912 clsW.lpfnWndProc = MsgCheckProcW;
9913 clsW.cbClsExtra = 0;
9914 clsW.cbWndExtra = 0;
9915 clsW.hInstance = GetModuleHandleW(0);
9916 clsW.hIcon = 0;
9917 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9918 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9919 clsW.lpszMenuName = NULL;
9920 clsW.lpszClassName = testWindowClassW;
9921 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
9922
9923 return TRUE;
9924 }
9925
9926 static BOOL is_our_logged_class(HWND hwnd)
9927 {
9928 char buf[256];
9929
9930 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9931 {
9932 if (!lstrcmpiA(buf, "TestWindowClass") ||
9933 !lstrcmpiA(buf, "ShowWindowClass") ||
9934 !lstrcmpiA(buf, "RecursiveActivationClass") ||
9935 !lstrcmpiA(buf, "TestParentClass") ||
9936 !lstrcmpiA(buf, "TestPopupClass") ||
9937 !lstrcmpiA(buf, "SimpleWindowClass") ||
9938 !lstrcmpiA(buf, "TestDialogClass") ||
9939 !lstrcmpiA(buf, "MDI_frame_class") ||
9940 !lstrcmpiA(buf, "MDI_client_class") ||
9941 !lstrcmpiA(buf, "MDI_child_class") ||
9942 !lstrcmpiA(buf, "my_button_class") ||
9943 !lstrcmpiA(buf, "my_edit_class") ||
9944 !lstrcmpiA(buf, "static") ||
9945 !lstrcmpiA(buf, "ListBox") ||
9946 !lstrcmpiA(buf, "ComboBox") ||
9947 !lstrcmpiA(buf, "MyDialogClass") ||
9948 !lstrcmpiA(buf, "#32770") ||
9949 !lstrcmpiA(buf, "#32768"))
9950 return TRUE;
9951 }
9952 return FALSE;
9953 }
9954
9955 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9956 {
9957 HWND hwnd;
9958
9959 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9960
9961 if (nCode == HCBT_CLICKSKIPPED)
9962 {
9963 /* ignore this event, XP sends it a lot when switching focus between windows */
9964 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9965 }
9966
9967 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9968 {
9969 struct recvd_message msg;
9970
9971 msg.hwnd = 0;
9972 msg.message = nCode;
9973 msg.flags = hook|wparam|lparam;
9974 msg.wParam = wParam;
9975 msg.lParam = lParam;
9976 msg.descr = "CBT";
9977 add_message(&msg);
9978
9979 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9980 }
9981
9982 if (nCode == HCBT_DESTROYWND)
9983 {
9984 if (test_DestroyWindow_flag)
9985 {
9986 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9987 if (style & WS_CHILD)
9988 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9989 else if (style & WS_POPUP)
9990 lParam = WND_POPUP_ID;
9991 else
9992 lParam = WND_PARENT_ID;
9993 }
9994 }
9995
9996 /* Log also SetFocus(0) calls */
9997 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9998
9999 if (is_our_logged_class(hwnd))
10000 {
10001 struct recvd_message msg;
10002
10003 msg.hwnd = hwnd;
10004 msg.message = nCode;
10005 msg.flags = hook|wparam|lparam;
10006 msg.wParam = wParam;
10007 msg.lParam = lParam;
10008 msg.descr = "CBT";
10009 add_message(&msg);
10010 }
10011 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10012 }
10013
10014 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
10015 DWORD event,
10016 HWND hwnd,
10017 LONG object_id,
10018 LONG child_id,
10019 DWORD thread_id,
10020 DWORD event_time)
10021 {
10022 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
10023
10024 /* ignore mouse cursor events */
10025 if (object_id == OBJID_CURSOR) return;
10026
10027 if (!hwnd || is_our_logged_class(hwnd))
10028 {
10029 struct recvd_message msg;
10030
10031 msg.hwnd = hwnd;
10032 msg.message = event;
10033 msg.flags = winevent_hook|wparam|lparam;
10034 msg.wParam = object_id;
10035 msg.lParam = child_id;
10036 msg.descr = "WEH";
10037 add_message(&msg);
10038 }
10039 }
10040
10041 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
10042 static const WCHAR wszAnsi[] = {'U',0};
10043
10044 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
10045 {
10046 switch (uMsg)
10047 {
10048 case CB_FINDSTRINGEXACT:
10049 trace("String: %p\n", (LPCWSTR)lParam);
10050 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
10051 return 1;
10052 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
10053 return 0;
10054 return -1;
10055 }
10056 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
10057 }
10058
10059 static const struct message WmGetTextLengthAfromW[] = {
10060 { WM_GETTEXTLENGTH, sent },
10061 { WM_GETTEXT, sent|optional },
10062 { 0 }
10063 };
10064
10065 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
10066
10067 /* dummy window proc for WM_GETTEXTLENGTH test */
10068 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
10069 {
10070 switch(msg)
10071 {
10072 case WM_GETTEXTLENGTH:
10073 return lstrlenW(dummy_window_text) + 37; /* some random length */
10074 case WM_GETTEXT:
10075 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
10076 return lstrlenW( (LPWSTR)lp );
10077 default:
10078 return DefWindowProcW( hwnd, msg, wp, lp );
10079 }
10080 }
10081
10082 static void test_message_conversion(void)
10083 {
10084 static const WCHAR wszMsgConversionClass[] =
10085 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
10086 WNDCLASSW cls;
10087 LRESULT lRes;
10088 HWND hwnd;
10089 WNDPROC wndproc, newproc;
10090 BOOL ret;
10091
10092 cls.style = 0;
10093 cls.lpfnWndProc = MsgConversionProcW;
10094 cls.cbClsExtra = 0;
10095 cls.cbWndExtra = 0;
10096 cls.hInstance = GetModuleHandleW(NULL);
10097 cls.hIcon = NULL;
10098 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
10099 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
10100 cls.lpszMenuName = NULL;
10101 cls.lpszClassName = wszMsgConversionClass;
10102 /* this call will fail on Win9x, but that doesn't matter as this test is
10103 * meaningless on those platforms */
10104 if(!RegisterClassW(&cls)) return;
10105
10106 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
10107 100, 100, 200, 200, 0, 0, 0, NULL);
10108 ok(hwnd != NULL, "Window creation failed\n");
10109
10110 /* {W, A} -> A */
10111
10112 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
10113 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10114 ok(lRes == 0, "String should have been converted\n");
10115 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10116 ok(lRes == 1, "String shouldn't have been converted\n");
10117
10118 /* {W, A} -> W */
10119
10120 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
10121 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10122 ok(lRes == 1, "String shouldn't have been converted\n");
10123 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10124 ok(lRes == 1, "String shouldn't have been converted\n");
10125
10126 /* Synchronous messages */
10127
10128 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10129 ok(lRes == 0, "String should have been converted\n");
10130 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10131 ok(lRes == 1, "String shouldn't have been converted\n");
10132
10133 /* Asynchronous messages */
10134
10135 SetLastError(0);
10136 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10137 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10138 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10139 SetLastError(0);
10140 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10141 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10142 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10143 SetLastError(0);
10144 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10145 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10146 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10147 SetLastError(0);
10148 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10149 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10150 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10151 SetLastError(0);
10152 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10153 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10154 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10155 SetLastError(0);
10156 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10157 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10158 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10159 SetLastError(0);
10160 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10161 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10162 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10163 SetLastError(0);
10164 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10165 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10166 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10167
10168 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
10169
10170 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
10171 WS_OVERLAPPEDWINDOW,
10172 100, 100, 200, 200, 0, 0, 0, NULL);
10173 assert(hwnd);
10174 flush_sequence();
10175 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
10176 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10177 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10178 "got bad length %ld\n", lRes );
10179
10180 flush_sequence();
10181 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
10182 hwnd, WM_GETTEXTLENGTH, 0, 0);
10183 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10184 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10185 "got bad length %ld\n", lRes );
10186
10187 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
10188 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
10189 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10190 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10191 NULL, 0, NULL, NULL ) ||
10192 broken(lRes == lstrlenW(dummy_window_text) + 37),
10193 "got bad length %ld\n", lRes );
10194
10195 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
10196 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10197 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10198 NULL, 0, NULL, NULL ) ||
10199 broken(lRes == lstrlenW(dummy_window_text) + 37),
10200 "got bad length %ld\n", lRes );
10201
10202 ret = DestroyWindow(hwnd);
10203 ok( ret, "DestroyWindow() error %d\n", GetLastError());
10204 }
10205
10206 struct timer_info
10207 {
10208 HWND hWnd;
10209 HANDLE handles[2];
10210 DWORD id;
10211 };
10212
10213 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
10214 {
10215 }
10216
10217 #define TIMER_ID 0x19
10218 #define TIMER_COUNT_EXPECTED 100
10219 #define TIMER_COUNT_TOLERANCE 10
10220
10221 static int count = 0;
10222 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10223 {
10224 count++;
10225 }
10226
10227 static DWORD exception;
10228 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10229 {
10230 count++;
10231 RaiseException(exception, 0, 0, NULL);
10232 }
10233
10234 static DWORD WINAPI timer_thread_proc(LPVOID x)
10235 {
10236 struct timer_info *info = x;
10237 DWORD r;
10238
10239 r = KillTimer(info->hWnd, 0x19);
10240 ok(r,"KillTimer failed in thread\n");
10241 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
10242 ok(r,"SetTimer failed in thread\n");
10243 ok(r==TIMER_ID,"SetTimer id different\n");
10244 r = SetEvent(info->handles[0]);
10245 ok(r,"SetEvent failed in thread\n");
10246 return 0;
10247 }
10248
10249 static void test_timers(void)
10250 {
10251 struct timer_info info;
10252 DWORD start;
10253 DWORD id;
10254 MSG msg;
10255
10256 info.hWnd = CreateWindowA("TestWindowClass", NULL,
10257 WS_OVERLAPPEDWINDOW ,
10258 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10259 NULL, NULL, 0);
10260
10261 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
10262 ok(info.id, "SetTimer failed\n");
10263 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
10264 info.handles[0] = CreateEventW(NULL,0,0,NULL);
10265 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
10266
10267 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
10268
10269 WaitForSingleObject(info.handles[1], INFINITE);
10270
10271 CloseHandle(info.handles[0]);
10272 CloseHandle(info.handles[1]);
10273
10274 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
10275
10276 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10277 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10278 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10279 * ±9 counts (~4 ms) around the expected value.
10280 */
10281 count = 0;
10282 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
10283 ok(id != 0, "did not get id from SetTimer.\n");
10284 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10285 start = GetTickCount();
10286 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10287 DispatchMessageA(&msg);
10288 ros_skip_flaky
10289 todo_wine
10290 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10291 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
10292 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
10293 "did not get expected count for minimum timeout (%d != ~%d).\n",
10294 count, TIMER_COUNT_EXPECTED);
10295 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
10296 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
10297 if (pSetSystemTimer)
10298 {
10299 int syscount = 0;
10300
10301 count = 0;
10302 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
10303 ok(id != 0, "did not get id from SetSystemTimer.\n");
10304 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10305 start = GetTickCount();
10306 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10307 {
10308 if (msg.message == WM_SYSTIMER)
10309 syscount++;
10310 DispatchMessageA(&msg);
10311 }
10312 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
10313 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
10314 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
10315 "did not get expected count for minimum timeout (%d != ~%d).\n",
10316 syscount, TIMER_COUNT_EXPECTED);
10317 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
10318 count);
10319 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10320 }
10321
10322 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10323 }
10324
10325 static void test_timers_no_wnd(void)
10326 {
10327 static UINT_PTR ids[0xffff];
10328 UINT_PTR id, id2;
10329 DWORD start;
10330 MSG msg;
10331 int i;
10332
10333 count = 0;
10334 id = SetTimer(NULL, 0, 100, callback_count);
10335 ok(id != 0, "did not get id from SetTimer.\n");
10336 id2 = SetTimer(NULL, id, 200, callback_count);
10337 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10338 Sleep(150);
10339 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10340 ok(count == 0, "did not get zero count as expected (%i).\n", count);
10341 Sleep(150);
10342 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10343 ok(count == 1, "did not get one count as expected (%i).\n", count);
10344 KillTimer(NULL, id);
10345 Sleep(250);
10346 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10347 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10348
10349 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10350 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10351 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10352 * ±9 counts (~4 ms) around the expected value.
10353 */
10354 count = 0;
10355 id = SetTimer(NULL, 0, 0, callback_count);
10356 ok(id != 0, "did not get id from SetTimer.\n");
10357 start = GetTickCount();
10358 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10359 DispatchMessageA(&msg);
10360 todo_wine
10361 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10362 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
10363 "did not get expected count for minimum timeout (%d != ~%d).\n",
10364 count, TIMER_COUNT_EXPECTED);
10365 KillTimer(NULL, id);
10366 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10367
10368 if (pSetCoalescableTimer)
10369 {
10370 count = 0;
10371 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10372 ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10373 start = GetTickCount();
10374 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10375 DispatchMessageA(&msg);
10376 ok(count > 1, "expected count > 1, got %d.\n", count);
10377 KillTimer(NULL, id);
10378 }
10379 else
10380 win_skip("SetCoalescableTimer not available.\n");
10381
10382 /* Check what happens when we're running out of timers */
10383 for (i = 0; i < ARRAY_SIZE(ids); i++)
10384 {
10385 SetLastError(0xdeadbeef);
10386 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10387 if (!ids[i]) break;
10388 }
10389 ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n");
10390 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10391 "GetLastError() = %d\n", GetLastError());
10392 while (i > 0) KillTimer(NULL, ids[--i]);
10393 }
10394
10395 static void test_timers_exception(DWORD code)
10396 {
10397 UINT_PTR id;
10398 MSG msg;
10399
10400 exception = code;
10401 id = SetTimer(NULL, 0, 1000, callback_exception);
10402 ok(id != 0, "did not get id from SetTimer.\n");
10403
10404 memset(&msg, 0, sizeof(msg));
10405 msg.message = WM_TIMER;
10406 msg.wParam = id;
10407 msg.lParam = (LPARAM)callback_exception;
10408
10409 count = 0;
10410 DispatchMessageA(&msg);
10411 ok(count == 1, "did not get one count as expected (%i).\n", count);
10412
10413 KillTimer(NULL, id);
10414 }
10415
10416 static void test_timers_exceptions(void)
10417 {
10418 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10419 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10420 test_timers_exception(EXCEPTION_BREAKPOINT);
10421 test_timers_exception(EXCEPTION_SINGLE_STEP);
10422 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10423 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10424 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10425 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10426 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10427 test_timers_exception(0xE000BEEF); /* customer exception */
10428 }
10429
10430 /* Various win events with arbitrary parameters */
10431 static const struct message WmWinEventsSeq[] = {
10432 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10433 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10434 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10435 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10436 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10437 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10438 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10439 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10440 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10441 /* our win event hook ignores OBJID_CURSOR events */
10442 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10443 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10444 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10445 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10446 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10447 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10448 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10449 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10450 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10451 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10452 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10453 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10454 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10455 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10456 { 0 }
10457 };
10458 static const struct message WmWinEventCaretSeq[] = {
10459 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10460 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10461 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10462 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10463 { 0 }
10464 };
10465 static const struct message WmWinEventCaretSeq_2[] = {
10466 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10467 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10468 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10469 { 0 }
10470 };
10471 static const struct message WmWinEventAlertSeq[] = {
10472 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10473 { 0 }
10474 };
10475 static const struct message WmWinEventAlertSeq_2[] = {
10476 /* create window in the thread proc */
10477 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10478 /* our test event */
10479 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10480 { 0 }
10481 };
10482 static const struct message WmGlobalHookSeq_1[] = {
10483 /* create window in the thread proc */
10484 { HCBT_CREATEWND, hook|lparam, 0, 2 },
10485 /* our test events */
10486 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10487 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10488 { 0 }
10489 };
10490 static const struct message WmGlobalHookSeq_2[] = {
10491 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10492 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10493 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10494 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10495 { 0 }
10496 };
10497
10498 static const struct message WmMouseLLHookSeq[] = {
10499 { WM_MOUSEMOVE, hook },
10500 { WM_LBUTTONUP, hook },
10501 { WM_MOUSEMOVE, hook },
10502 { 0 }
10503 };
10504
10505 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10506 DWORD event,
10507 HWND hwnd,
10508 LONG object_id,
10509 LONG child_id,
10510 DWORD thread_id,
10511 DWORD event_time)
10512 {
10513 char buf[256];
10514
10515 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10516 {
10517 if (!lstrcmpiA(buf, "TestWindowClass") ||
10518 !lstrcmpiA(buf, "static"))
10519 {
10520 struct recvd_message msg;
10521
10522 msg.hwnd = hwnd;
10523 msg.message = event;
10524 msg.flags = winevent_hook|wparam|lparam;
10525 msg.wParam = object_id;
10526 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10527 msg.descr = "WEH_2";
10528 add_message(&msg);
10529 }
10530 }
10531 }
10532
10533 static HHOOK hCBT_global_hook;
10534 static DWORD cbt_global_hook_thread_id;
10535
10536 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10537 {
10538 HWND hwnd;
10539 char buf[256];
10540
10541 if (nCode == HCBT_SYSCOMMAND)
10542 {
10543 struct recvd_message msg;
10544
10545 msg.hwnd = 0;
10546 msg.message = nCode;
10547 msg.flags = hook|wparam|lparam;
10548 msg.wParam = wParam;
10549 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10550 msg.descr = "CBT_2";
10551 add_message(&msg);
10552
10553 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10554 }
10555 /* WH_MOUSE_LL hook */
10556 if (nCode == HC_ACTION)
10557 {
10558 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10559
10560 /* we can't test for real mouse events */
10561 if (mhll->flags & LLMHF_INJECTED)
10562 {
10563 struct recvd_message msg;
10564
10565 memset (&msg, 0, sizeof (msg));
10566 msg.message = wParam;
10567 msg.flags = hook;
10568 msg.descr = "CBT_2";
10569 add_message(&msg);
10570 }
10571 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10572 }
10573
10574 /* Log also SetFocus(0) calls */
10575 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10576
10577 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10578 {
10579 if (!lstrcmpiA(buf, "TestWindowClass") ||
10580 !lstrcmpiA(buf, "static"))
10581 {
10582 struct recvd_message msg;
10583
10584 msg.hwnd = hwnd;
10585 msg.message = nCode;
10586 msg.flags = hook|wparam|lparam;
10587 msg.wParam = wParam;
10588 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10589 msg.descr = "CBT_2";
10590 add_message(&msg);
10591 }
10592 }
10593 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10594 }
10595
10596 static DWORD WINAPI win_event_global_thread_proc(void *param)
10597 {
10598 HWND hwnd;
10599 MSG msg;
10600 HANDLE hevent = *(HANDLE *)param;
10601
10602 assert(pNotifyWinEvent);
10603
10604 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10605 assert(hwnd);
10606 trace("created thread window %p\n", hwnd);
10607
10608 *(HWND *)param = hwnd;
10609
10610 flush_sequence();
10611 /* this event should be received only by our new hook proc,
10612 * an old one does not expect an event from another thread.
10613 */
10614 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10615 SetEvent(hevent);
10616
10617 while (GetMessageA(&msg, 0, 0, 0))
10618 {
10619 TranslateMessage(&msg);
10620 DispatchMessageA(&msg);
10621 }
10622 return 0;
10623 }
10624
10625 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10626 {
10627 HWND hwnd;
10628 MSG msg;
10629 HANDLE hevent = *(HANDLE *)param;
10630
10631 flush_sequence();
10632 /* these events should be received only by our new hook proc,
10633 * an old one does not expect an event from another thread.
10634 */
10635
10636 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10637 assert(hwnd);
10638 trace("created thread window %p\n", hwnd);
10639
10640 *(HWND *)param = hwnd;
10641
10642 /* Windows doesn't like when a thread plays games with the focus,
10643 that leads to all kinds of misbehaviours and failures to activate
10644 a window. So, better keep next lines commented out.
10645 SetFocus(0);
10646 SetFocus(hwnd);*/
10647
10648 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10649 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10650
10651 SetEvent(hevent);
10652
10653 while (GetMessageA(&msg, 0, 0, 0))
10654 {
10655 TranslateMessage(&msg);
10656 DispatchMessageA(&msg);
10657 }
10658 return 0;
10659 }
10660
10661 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10662 {
10663 HWND hwnd;
10664 MSG msg;
10665 HANDLE hevent = *(HANDLE *)param;
10666
10667 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10668 assert(hwnd);
10669 trace("created thread window %p\n", hwnd);
10670
10671 *(HWND *)param = hwnd;
10672
10673 flush_sequence();
10674
10675 /* Windows doesn't like when a thread plays games with the focus,
10676 * that leads to all kinds of misbehaviours and failures to activate
10677 * a window. So, better don't generate a mouse click message below.
10678 */
10679 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10680 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10681 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10682
10683 SetEvent(hevent);
10684 while (GetMessageA(&msg, 0, 0, 0))
10685 {
10686 TranslateMessage(&msg);
10687 DispatchMessageA(&msg);
10688 }
10689 return 0;
10690 }
10691
10692 static void test_winevents(void)
10693 {
10694 BOOL ret;
10695 MSG msg;
10696 HWND hwnd, hwnd2;
10697 UINT i;
10698 HANDLE hthread, hevent;
10699 DWORD tid;
10700 HWINEVENTHOOK hhook;
10701 const struct message *events = WmWinEventsSeq;
10702
10703 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10704 WS_OVERLAPPEDWINDOW,
10705 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10706 NULL, NULL, 0);
10707 assert(hwnd);
10708
10709 /****** start of global hook test *************/
10710 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10711 if (!hCBT_global_hook)
10712 {
10713 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10714 skip( "cannot set global hook\n" );
10715 return;
10716 }
10717
10718 hevent = CreateEventA(NULL, 0, 0, NULL);
10719 assert(hevent);
10720 hwnd2 = hevent;
10721
10722 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10723 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10724
10725 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10726
10727 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10728
10729 flush_sequence();
10730 /* this one should be received only by old hook proc */
10731 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10732 /* this one should be received only by old hook proc */
10733 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10734
10735 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10736
10737 ret = UnhookWindowsHookEx(hCBT_global_hook);
10738 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10739
10740 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10741 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10742 CloseHandle(hthread);
10743 CloseHandle(hevent);
10744 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10745 /****** end of global hook test *************/
10746
10747 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10748 {
10749 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10750 return;
10751 }
10752
10753 flush_sequence();
10754
10755 if (0)
10756 {
10757 /* this test doesn't pass under Win9x */
10758 /* win2k ignores events with hwnd == 0 */
10759 SetLastError(0xdeadbeef);
10760 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10761 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10762 GetLastError() == 0xdeadbeef, /* Win9x */
10763 "unexpected error %d\n", GetLastError());
10764 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10765 }
10766
10767 for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++)
10768 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10769
10770 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10771
10772 /****** start of event filtering test *************/
10773 hhook = pSetWinEventHook(
10774 EVENT_OBJECT_SHOW, /* 0x8002 */
10775 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10776 GetModuleHandleA(0), win_event_global_hook_proc,
10777 GetCurrentProcessId(), 0,
10778 WINEVENT_INCONTEXT);
10779 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10780
10781 hevent = CreateEventA(NULL, 0, 0, NULL);
10782 assert(hevent);
10783 hwnd2 = hevent;
10784
10785 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10786 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10787
10788 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10789
10790 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10791
10792 flush_sequence();
10793 /* this one should be received only by old hook proc */
10794 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10795 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10796 /* this one should be received only by old hook proc */
10797 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10798
10799 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10800
10801 ret = pUnhookWinEvent(hhook);
10802 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10803
10804 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10805 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10806 CloseHandle(hthread);
10807 CloseHandle(hevent);
10808 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10809 /****** end of event filtering test *************/
10810
10811 /****** start of out of context event test *************/
10812 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10813 win_event_global_hook_proc, GetCurrentProcessId(), 0,
10814 WINEVENT_OUTOFCONTEXT);
10815 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10816
10817 hevent = CreateEventA(NULL, 0, 0, NULL);
10818 assert(hevent);
10819 hwnd2 = hevent;
10820
10821 flush_sequence();
10822
10823 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10824 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10825
10826 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10827
10828 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10829 /* process pending winevent messages */
10830 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10831 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10832
10833 flush_sequence();
10834 /* this one should be received only by old hook proc */
10835 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10836 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10837 /* this one should be received only by old hook proc */
10838 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10839
10840 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10841 /* process pending winevent messages */
10842 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10843 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10844
10845 ret = pUnhookWinEvent(hhook);
10846 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10847
10848 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10849 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10850 CloseHandle(hthread);
10851 CloseHandle(hevent);
10852 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10853 /****** end of out of context event test *************/
10854
10855 /****** start of MOUSE_LL hook test *************/
10856 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10857 /* WH_MOUSE_LL is not supported on Win9x platforms */
10858 if (!hCBT_global_hook)
10859 {
10860 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10861 goto skip_mouse_ll_hook_test;
10862 }
10863
10864 hevent = CreateEventA(NULL, 0, 0, NULL);
10865 assert(hevent);
10866 hwnd2 = hevent;
10867
10868 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10869 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10870
10871 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10872 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10873
10874 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10875 flush_sequence();
10876
10877 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10878 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10879 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10880
10881 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10882
10883 ret = UnhookWindowsHookEx(hCBT_global_hook);
10884 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10885
10886 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10887 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10888 CloseHandle(hthread);
10889 CloseHandle(hevent);
10890 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10891 /****** end of MOUSE_LL hook test *************/
10892 skip_mouse_ll_hook_test:
10893
10894 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10895 }
10896
10897 static void test_set_hook(void)
10898 {
10899 BOOL ret;
10900 HHOOK hhook;
10901 HWINEVENTHOOK hwinevent_hook;
10902
10903 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10904 ok(hhook != 0, "local hook does not require hModule set to 0\n");
10905 UnhookWindowsHookEx(hhook);
10906
10907 if (0)
10908 {
10909 /* this test doesn't pass under Win9x: BUG! */
10910 SetLastError(0xdeadbeef);
10911 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10912 ok(!hhook, "global hook requires hModule != 0\n");
10913 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10914 }
10915
10916 SetLastError(0xdeadbeef);
10917 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10918 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10919 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10920 GetLastError() == 0xdeadbeef, /* Win9x */
10921 "unexpected error %d\n", GetLastError());
10922
10923 SetLastError(0xdeadbeef);
10924 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10925 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10926 GetLastError() == 0xdeadbeef, /* Win9x */
10927 "unexpected error %d\n", GetLastError());
10928
10929 if (!pSetWinEventHook || !pUnhookWinEvent) return;
10930
10931 /* even process local incontext hooks require hmodule */
10932 SetLastError(0xdeadbeef);
10933 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10934 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10935 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10936 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10937 GetLastError() == 0xdeadbeef, /* Win9x */
10938 "unexpected error %d\n", GetLastError());
10939
10940 /* even thread local incontext hooks require hmodule */
10941 SetLastError(0xdeadbeef);
10942 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10943 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10944 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10945 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10946 GetLastError() == 0xdeadbeef, /* Win9x */
10947 "unexpected error %d\n", GetLastError());
10948
10949 if (0)
10950 {
10951 /* these 3 tests don't pass under Win9x */
10952 SetLastError(0xdeadbeef);
10953 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10954 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10955 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10956 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10957
10958 SetLastError(0xdeadbeef);
10959 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10960 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10961 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10962 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10963
10964 SetLastError(0xdeadbeef);
10965 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10966 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10967 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10968 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10969 }
10970
10971 SetLastError(0xdeadbeef);
10972 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10973 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10974 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10975 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10976 ret = pUnhookWinEvent(hwinevent_hook);
10977 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10978
10979 todo_wine {
10980 /* This call succeeds under win2k SP4, but fails under Wine.
10981 Does win2k test/use passed process id? */
10982 SetLastError(0xdeadbeef);
10983 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10984 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10985 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10986 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10987 ret = pUnhookWinEvent(hwinevent_hook);
10988 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10989 }
10990
10991 SetLastError(0xdeadbeef);
10992 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10993 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10994 GetLastError() == 0xdeadbeef, /* Win9x */
10995 "unexpected error %d\n", GetLastError());
10996 }
10997
10998 static HWND hook_hwnd;
10999 static HHOOK recursive_hook;
11000 static int hook_depth, max_hook_depth;
11001
11002 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
11003 {
11004 LRESULT res;
11005 MSG msg;
11006 BOOL b;
11007
11008 hook_depth++;
11009 if(hook_depth > max_hook_depth)
11010 max_hook_depth = hook_depth;
11011
11012 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
11013 ok(b, "PeekMessage failed\n");
11014
11015 res = CallNextHookEx(recursive_hook, code, w, l);
11016
11017 hook_depth--;
11018 return res;
11019 }
11020
11021 static void test_recursive_hook(void)
11022 {
11023 MSG msg;
11024 BOOL b;
11025
11026 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
11027 ok(hook_hwnd != NULL, "CreateWindow failed\n");
11028
11029 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
11030 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
11031
11032 PostMessageW(hook_hwnd, WM_USER, 0, 0);
11033 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
11034
11035 hook_depth = 0;
11036 GetMessageW(&msg, hook_hwnd, 0, 0);
11037 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
11038 trace("max_hook_depth = %d\n", max_hook_depth);
11039
11040 b = UnhookWindowsHookEx(recursive_hook);
11041 ok(b, "UnhokWindowsHookEx failed\n");
11042
11043 DestroyWindow(hook_hwnd);
11044 }
11045
11046 static const struct message ScrollWindowPaint1[] = {
11047 { WM_PAINT, sent },
11048 { WM_ERASEBKGND, sent|beginpaint },
11049 { WM_GETTEXTLENGTH, sent|optional },
11050 { WM_PAINT, sent|optional },
11051 { WM_NCPAINT, sent|beginpaint|optional },
11052 { WM_GETTEXT, sent|beginpaint|optional },
11053 { WM_GETTEXT, sent|beginpaint|optional },
11054 { WM_GETTEXT, sent|beginpaint|optional },
11055 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
11056 { WM_ERASEBKGND, sent|beginpaint|optional },
11057 { 0 }
11058 };
11059
11060 static const struct message ScrollWindowPaint2[] = {
11061 { WM_PAINT, sent },
11062 { 0 }
11063 };
11064
11065 static void test_scrollwindowex(void)
11066 {
11067 HWND hwnd, hchild;
11068 RECT rect={0,0,130,130};
11069
11070 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
11071 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
11072 100, 100, 200, 200, 0, 0, 0, NULL);
11073 ok (hwnd != 0, "Failed to create overlapped window\n");
11074 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
11075 WS_VISIBLE|WS_CAPTION|WS_CHILD,
11076 10, 10, 150, 150, hwnd, 0, 0, NULL);
11077 ok (hchild != 0, "Failed to create child\n");
11078 UpdateWindow(hwnd);
11079 flush_events();
11080 flush_sequence();
11081
11082 /* scroll without the child window */
11083 trace("start scroll\n");
11084 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11085 SW_ERASE|SW_INVALIDATE);
11086 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11087 trace("end scroll\n");
11088 flush_sequence();
11089 flush_events();
11090 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11091 flush_events();
11092 flush_sequence();
11093
11094 /* Now without the SW_ERASE flag */
11095 trace("start scroll\n");
11096 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
11097 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11098 trace("end scroll\n");
11099 flush_sequence();
11100 flush_events();
11101 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
11102 flush_events();
11103 flush_sequence();
11104
11105 /* now scroll the child window as well */
11106 trace("start scroll\n");
11107 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11108 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
11109 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
11110 /* windows sometimes a WM_MOVE */
11111 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
11112 trace("end scroll\n");
11113 flush_sequence();
11114 flush_events();
11115 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11116 flush_events();
11117 flush_sequence();
11118
11119 /* now scroll with ScrollWindow() */
11120 trace("start scroll with ScrollWindow\n");
11121 ScrollWindow( hwnd, 5, 5, NULL, NULL);
11122 trace("end scroll\n");
11123 flush_sequence();
11124 flush_events();
11125 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
11126
11127 ok(DestroyWindow(hchild), "failed to destroy window\n");
11128 ok(DestroyWindow(hwnd), "failed to destroy window\n");
11129 flush_sequence();
11130 }
11131
11132 static const struct message destroy_window_with_children[] = {
11133 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11134 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
11135 { 0x0090, sent|optional },
11136 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
11137 { 0x0090, sent|optional },
11138 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11139 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11140 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11141 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11142 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
11143 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11144 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11145 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11146 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11147 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11148 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11149 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11150 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11151 { 0 }
11152 };
11153
11154 static void test_DestroyWindow(void)
11155 {
11156 BOOL ret;
11157 HWND parent, child1, child2, child3, child4, test;
11158 UINT_PTR child_id = WND_CHILD_ID + 1;
11159
11160 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11161 100, 100, 200, 200, 0, 0, 0, NULL);
11162 assert(parent != 0);
11163 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11164 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
11165 assert(child1 != 0);
11166 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11167 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
11168 assert(child2 != 0);
11169 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11170 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
11171 assert(child3 != 0);
11172 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
11173 0, 0, 50, 50, parent, 0, 0, NULL);
11174 assert(child4 != 0);
11175
11176 /* test owner/parent of child2 */
11177 test = GetParent(child2);
11178 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11179 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11180 if(pGetAncestor) {
11181 test = pGetAncestor(child2, GA_PARENT);
11182 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11183 }
11184 test = GetWindow(child2, GW_OWNER);
11185 ok(!test, "wrong owner %p\n", test);
11186
11187 test = SetParent(child2, parent);
11188 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
11189
11190 /* test owner/parent of the parent */
11191 test = GetParent(parent);
11192 ok(!test, "wrong parent %p\n", test);
11193 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
11194 if(pGetAncestor) {
11195 test = pGetAncestor(parent, GA_PARENT);
11196 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11197 }
11198 test = GetWindow(parent, GW_OWNER);
11199 ok(!test, "wrong owner %p\n", test);
11200
11201 /* test owner/parent of child1 */
11202 test = GetParent(child1);
11203 ok(test == parent, "wrong parent %p\n", test);
11204 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
11205 if(pGetAncestor) {
11206 test = pGetAncestor(child1, GA_PARENT);
11207 ok(test == parent, "wrong parent %p\n", test);
11208 }
11209 test = GetWindow(child1, GW_OWNER);
11210 ok(!test, "wrong owner %p\n", test);
11211
11212 /* test owner/parent of child2 */
11213 test = GetParent(child2);
11214 ok(test == parent, "wrong parent %p\n", test);
11215 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11216 if(pGetAncestor) {
11217 test = pGetAncestor(child2, GA_PARENT);
11218 ok(test == parent, "wrong parent %p\n", test);
11219 }
11220 test = GetWindow(child2, GW_OWNER);
11221 ok(!test, "wrong owner %p\n", test);
11222
11223 /* test owner/parent of child3 */
11224 test = GetParent(child3);
11225 ok(test == child1, "wrong parent %p\n", test);
11226 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
11227 if(pGetAncestor) {
11228 test = pGetAncestor(child3, GA_PARENT);
11229 ok(test == child1, "wrong parent %p\n", test);
11230 }
11231 test = GetWindow(child3, GW_OWNER);
11232 ok(!test, "wrong owner %p\n", test);
11233
11234 /* test owner/parent of child4 */
11235 test = GetParent(child4);
11236 ok(test == parent, "wrong parent %p\n", test);
11237 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
11238 if(pGetAncestor) {
11239 test = pGetAncestor(child4, GA_PARENT);
11240 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11241 }
11242 test = GetWindow(child4, GW_OWNER);
11243 ok(test == parent, "wrong owner %p\n", test);
11244
11245 flush_sequence();
11246
11247 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
11248 parent, child1, child2, child3, child4);
11249
11250 SetCapture(child4);
11251 test = GetCapture();
11252 ok(test == child4, "wrong capture window %p\n", test);
11253
11254 test_DestroyWindow_flag = TRUE;
11255 ret = DestroyWindow(parent);
11256 ok( ret, "DestroyWindow() error %d\n", GetLastError());
11257 test_DestroyWindow_flag = FALSE;
11258 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
11259
11260 ok(!IsWindow(parent), "parent still exists\n");
11261 ok(!IsWindow(child1), "child1 still exists\n");
11262 ok(!IsWindow(child2), "child2 still exists\n");
11263 ok(!IsWindow(child3), "child3 still exists\n");
11264 ok(!IsWindow(child4), "child4 still exists\n");
11265
11266 test = GetCapture();
11267 ok(!test, "wrong capture window %p\n", test);
11268 }
11269
11270
11271 static const struct message WmDispatchPaint[] = {
11272 { WM_NCPAINT, sent },
11273 { WM_GETTEXT, sent|defwinproc|optional },
11274 { WM_GETTEXT, sent|defwinproc|optional },
11275 { WM_ERASEBKGND, sent },
11276 { 0 }
11277 };
11278
11279 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11280 {
11281 if (message == WM_PAINT) return 0;
11282 return MsgCheckProcA( hwnd, message, wParam, lParam );
11283 }
11284
11285 static void test_DispatchMessage(void)
11286 {
11287 RECT rect;
11288 MSG msg;
11289 int count;
11290 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11291 100, 100, 200, 200, 0, 0, 0, NULL);
11292 ShowWindow( hwnd, SW_SHOW );
11293 UpdateWindow( hwnd );
11294 flush_events();
11295 flush_sequence();
11296 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
11297
11298 SetRect( &rect, -5, -5, 5, 5 );
11299 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11300 count = 0;
11301 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11302 {
11303 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11304 else
11305 {
11306 flush_sequence();
11307 DispatchMessageA( &msg );
11308 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
11309 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11310 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
11311 if (++count > 10) break;
11312 }
11313 }
11314 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
11315
11316 trace("now without DispatchMessage\n");
11317 flush_sequence();
11318 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11319 count = 0;
11320 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11321 {
11322 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11323 else
11324 {
11325 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11326 flush_sequence();
11327 /* this will send WM_NCCPAINT just like DispatchMessage does */
11328 GetUpdateRgn( hwnd, hrgn, TRUE );
11329 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11330 DeleteObject( hrgn );
11331 GetClientRect( hwnd, &rect );
11332 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
11333 ok( !count, "Got multiple WM_PAINTs\n" );
11334 if (++count > 10) break;
11335 }
11336 }
11337
11338 flush_sequence();
11339 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11340 count = 0;
11341 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11342 {
11343 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11344 else
11345 {
11346 HDC hdc;
11347
11348 flush_sequence();
11349 hdc = BeginPaint( hwnd, NULL );
11350 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11351 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11352 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11353 ok( !count, "Got multiple WM_PAINTs\n" );
11354 if (++count > 10) break;
11355 }
11356 }
11357 DestroyWindow(hwnd);
11358 }
11359
11360
11361 static const struct message WmUser[] = {
11362 { WM_USER, sent },
11363 { 0 }
11364 };
11365
11366 struct sendmsg_info
11367 {
11368 HWND hwnd;
11369 DWORD timeout;
11370 DWORD ret;
11371 };
11372
11373 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11374 {
11375 struct sendmsg_info *info = arg;
11376 SetLastError( 0xdeadbeef );
11377 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11378 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11379 broken(GetLastError() == 0), /* win9x */
11380 "unexpected error %d\n", GetLastError());
11381 return 0;
11382 }
11383
11384 static void wait_for_thread( HANDLE thread )
11385 {
11386 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11387 {
11388 MSG msg;
11389 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11390 }
11391 }
11392
11393 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11394 {
11395 if (message == WM_USER) Sleep(200);
11396 return MsgCheckProcA( hwnd, message, wParam, lParam );
11397 }
11398
11399 static void test_SendMessageTimeout(void)
11400 {
11401 HANDLE thread;
11402 struct sendmsg_info info;
11403 DWORD tid;
11404 BOOL is_win9x;
11405
11406 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11407 100, 100, 200, 200, 0, 0, 0, NULL);
11408 flush_events();
11409 flush_sequence();
11410
11411 info.timeout = 1000;
11412 info.ret = 0xdeadbeef;
11413 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11414 wait_for_thread( thread );
11415 CloseHandle( thread );
11416 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11417 ok_sequence( WmUser, "WmUser", FALSE );
11418
11419 info.timeout = 1;
11420 info.ret = 0xdeadbeef;
11421 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11422 Sleep(100); /* SendMessageTimeout should time out here */
11423 wait_for_thread( thread );
11424 CloseHandle( thread );
11425 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11426 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11427
11428 /* 0 means infinite timeout (but not on win9x) */
11429 info.timeout = 0;
11430 info.ret = 0xdeadbeef;
11431 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11432 Sleep(100);
11433 wait_for_thread( thread );
11434 CloseHandle( thread );
11435 is_win9x = !info.ret;
11436 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11437 else ok_sequence( WmUser, "WmUser", FALSE );
11438
11439 /* timeout is treated as signed despite the prototype (but not on win9x) */
11440 info.timeout = 0x7fffffff;
11441 info.ret = 0xdeadbeef;
11442 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11443 Sleep(100);
11444 wait_for_thread( thread );
11445 CloseHandle( thread );
11446 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11447 ok_sequence( WmUser, "WmUser", FALSE );
11448
11449 info.timeout = 0x80000000;
11450 info.ret = 0xdeadbeef;
11451 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11452 Sleep(100);
11453 wait_for_thread( thread );
11454 CloseHandle( thread );
11455 if (is_win9x)
11456 {
11457 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11458 ok_sequence( WmUser, "WmUser", FALSE );
11459 }
11460 else
11461 {
11462 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11463 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11464 }
11465
11466 /* now check for timeout during message processing */
11467 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11468 info.timeout = 100;
11469 info.ret = 0xdeadbeef;
11470 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11471 wait_for_thread( thread );
11472 CloseHandle( thread );
11473 /* we should time out but still get the message */
11474 ok( info.ret == 0, "SendMessageTimeout failed\n" );
11475 ok_sequence( WmUser, "WmUser", FALSE );
11476
11477 DestroyWindow( info.hwnd );
11478 }
11479
11480
11481 /****************** edit message test *************************/
11482 #define ID_EDIT 0x1234
11483 static const struct message sl_edit_setfocus[] =
11484 {
11485 { HCBT_SETFOCUS, hook },
11486 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11487 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11488 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11489 { WM_SETFOCUS, sent|wparam, 0 },
11490 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11491 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11492 { WM_CTLCOLOREDIT, sent|parent },
11493 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11494 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11495 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11496 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11497 { 0 }
11498 };
11499 static const struct message sl_edit_invisible[] =
11500 {
11501 { HCBT_SETFOCUS, hook },
11502 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11503 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11504 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11505 { WM_KILLFOCUS, sent|parent },
11506 { WM_SETFOCUS, sent },
11507 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11508 { 0 }
11509 };
11510 static const struct message ml_edit_setfocus[] =
11511 {
11512 { HCBT_SETFOCUS, hook },
11513 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11514 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11515 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11516 { WM_SETFOCUS, sent|wparam, 0 },
11517 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11518 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11519 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11520 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11521 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11522 { 0 }
11523 };
11524 static const struct message sl_edit_killfocus[] =
11525 {
11526 { HCBT_SETFOCUS, hook },
11527 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11528 { WM_KILLFOCUS, sent|wparam, 0 },
11529 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11530 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11531 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11532 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11533 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11534 { 0 }
11535 };
11536 static const struct message sl_edit_lbutton_dblclk[] =
11537 {
11538 { WM_LBUTTONDBLCLK, sent },
11539 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11540 { 0 }
11541 };
11542 static const struct message sl_edit_lbutton_down[] =
11543 {
11544 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11545 { HCBT_SETFOCUS, hook },
11546 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11547 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11548 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11549 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11550 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11551 { WM_CTLCOLOREDIT, sent|parent },
11552 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11553 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11554 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11555 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11556 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11557 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11558 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11559 { WM_CTLCOLOREDIT, sent|parent|optional },
11560 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11561 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11562 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11563 { 0 }
11564 };
11565 static const struct message ml_edit_lbutton_down[] =
11566 {
11567 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11568 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11569 { HCBT_SETFOCUS, hook },
11570 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11571 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11572 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11573 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11574 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11575 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11576 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11577 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11578 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11579 { 0 }
11580 };
11581 static const struct message sl_edit_lbutton_up[] =
11582 {
11583 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11584 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11585 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11586 { WM_CAPTURECHANGED, sent|defwinproc },
11587 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11588 { 0 }
11589 };
11590 static const struct message ml_edit_lbutton_up[] =
11591 {
11592 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11593 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11594 { WM_CAPTURECHANGED, sent|defwinproc },
11595 { 0 }
11596 };
11597
11598 static WNDPROC old_edit_proc;
11599
11600 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11601 {
11602 static LONG defwndproc_counter = 0;
11603 LRESULT ret;
11604 struct recvd_message msg;
11605
11606 if (ignore_message( message )) return 0;
11607
11608 msg.hwnd = hwnd;
11609 msg.message = message;
11610 msg.flags = sent|wparam|lparam;
11611 if (defwndproc_counter) msg.flags |= defwinproc;
11612 msg.wParam = wParam;
11613 msg.lParam = lParam;
11614 msg.descr = "edit";
11615 add_message(&msg);
11616
11617 defwndproc_counter++;
11618 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11619 defwndproc_counter--;
11620
11621 return ret;
11622 }
11623
11624 static void subclass_edit(void)
11625 {
11626 WNDCLASSA cls;
11627
11628 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11629
11630 old_edit_proc = cls.lpfnWndProc;
11631
11632 cls.hInstance = GetModuleHandleA(NULL);
11633 cls.lpfnWndProc = edit_hook_proc;
11634 cls.lpszClassName = "my_edit_class";
11635 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11636 if (!RegisterClassA(&cls)) assert(0);
11637 }
11638
11639 static void test_edit_messages(void)
11640 {
11641 HWND hwnd, parent;
11642 DWORD dlg_code;
11643
11644 subclass_edit();
11645 log_all_parent_messages++;
11646
11647 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11648 100, 100, 200, 200, 0, 0, 0, NULL);
11649 ok (parent != 0, "Failed to create parent window\n");
11650
11651 /* test single line edit */
11652 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11653 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11654 ok(hwnd != 0, "Failed to create edit window\n");
11655
11656 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11657 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11658
11659 flush_sequence();
11660 SetFocus(hwnd);
11661 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11662
11663 ShowWindow(hwnd, SW_SHOW);
11664 UpdateWindow(hwnd);
11665 SetFocus(0);
11666 flush_sequence();
11667
11668 SetFocus(hwnd);
11669 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11670
11671 SetFocus(0);
11672 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11673
11674 SetFocus(0);
11675 ReleaseCapture();
11676 flush_sequence();
11677
11678 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11679 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11680
11681 SetFocus(0);
11682 ReleaseCapture();
11683 flush_sequence();
11684
11685 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11686 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11687
11688 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11689 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11690
11691 DestroyWindow(hwnd);
11692
11693 /* test multiline edit */
11694 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11695 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11696 ok(hwnd != 0, "Failed to create edit window\n");
11697
11698 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11699 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11700 "wrong dlg_code %08x\n", dlg_code);
11701
11702 ShowWindow(hwnd, SW_SHOW);
11703 UpdateWindow(hwnd);
11704 SetFocus(0);
11705 flush_sequence();
11706
11707 SetFocus(hwnd);
11708 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11709
11710 SetFocus(0);
11711 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11712
11713 SetFocus(0);
11714 ReleaseCapture();
11715 flush_sequence();
11716
11717 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11718 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11719
11720 SetFocus(0);
11721 ReleaseCapture();
11722 flush_sequence();
11723
11724 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11725 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11726
11727 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11728 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11729
11730 DestroyWindow(hwnd);
11731 DestroyWindow(parent);
11732
11733 log_all_parent_messages--;
11734 }
11735
11736 /**************************** End of Edit test ******************************/
11737
11738 static const struct message WmKeyDownSkippedSeq[] =
11739 {
11740 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11741 { 0 }
11742 };
11743 static const struct message WmKeyDownWasDownSkippedSeq[] =
11744 {
11745 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11746 { 0 }
11747 };
11748 static const struct message WmKeyUpSkippedSeq[] =
11749 {
11750 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11751 { 0 }
11752 };
11753 static const struct message WmUserKeyUpSkippedSeq[] =
11754 {
11755 { WM_USER, sent },
11756 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11757 { 0 }
11758 };
11759
11760 #define EV_STOP 0
11761 #define EV_SENDMSG 1
11762 #define EV_ACK 2
11763
11764 struct peekmsg_info
11765 {
11766 HWND hwnd;
11767 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11768 };
11769
11770 static DWORD CALLBACK send_msg_thread_2(void *param)
11771 {
11772 DWORD ret;
11773 struct peekmsg_info *info = param;
11774
11775 trace("thread: looping\n");
11776 SetEvent(info->hevent[EV_ACK]);
11777
11778 while (1)
11779 {
11780 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
11781
11782 switch (ret)
11783 {
11784 case WAIT_OBJECT_0 + EV_STOP:
11785 trace("thread: exiting\n");
11786 return 0;
11787
11788 case WAIT_OBJECT_0 + EV_SENDMSG:
11789 trace("thread: sending message\n");
11790 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11791 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11792 SetEvent(info->hevent[EV_ACK]);
11793 break;
11794
11795 default:
11796 trace("unexpected return: %04x\n", ret);
11797 assert(0);
11798 break;
11799 }
11800 }
11801 return 0;
11802 }
11803
11804 static void test_PeekMessage(void)
11805 {
11806 MSG msg;
11807 HANDLE hthread;
11808 DWORD tid, qstatus;
11809 UINT qs_all_input = QS_ALLINPUT;
11810 UINT qs_input = QS_INPUT;
11811 BOOL ret;
11812 struct peekmsg_info info;
11813
11814 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11815 100, 100, 200, 200, 0, 0, 0, NULL);
11816 assert(info.hwnd);
11817 ShowWindow(info.hwnd, SW_SHOW);
11818 UpdateWindow(info.hwnd);
11819 SetFocus(info.hwnd);
11820
11821 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11822 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11823 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11824
11825 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11826 WaitForSingleObject(info.hevent[EV_ACK], 10000);
11827
11828 flush_events();
11829 flush_sequence();
11830
11831 SetLastError(0xdeadbeef);
11832 qstatus = GetQueueStatus(qs_all_input);
11833 if (GetLastError() == ERROR_INVALID_FLAGS)
11834 {
11835 trace("QS_RAWINPUT not supported on this platform\n");
11836 qs_all_input &= ~QS_RAWINPUT;
11837 qs_input &= ~QS_RAWINPUT;
11838 }
11839 if (qstatus & QS_POSTMESSAGE)
11840 {
11841 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11842 qstatus = GetQueueStatus(qs_all_input);
11843 }
11844 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11845
11846 trace("signalling to send message\n");
11847 SetEvent(info.hevent[EV_SENDMSG]);
11848 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11849
11850 /* pass invalid QS_xxxx flags */
11851 SetLastError(0xdeadbeef);
11852 qstatus = GetQueueStatus(0xffffffff);
11853 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11854 if (!qstatus)
11855 {
11856 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11857 qstatus = GetQueueStatus(qs_all_input);
11858 }
11859 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
11860 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11861 "wrong qstatus %08x\n", qstatus);
11862
11863 msg.message = 0;
11864 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11865 ok(!ret,
11866 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11867 msg.message);
11868 ok_sequence(WmUser, "WmUser", FALSE);
11869
11870 qstatus = GetQueueStatus(qs_all_input);
11871 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11872
11873 keybd_event('N', 0, 0, 0);
11874 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11875 qstatus = GetQueueStatus(qs_all_input);
11876 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11877 {
11878 skip( "queuing key events not supported\n" );
11879 goto done;
11880 }
11881 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11882 /* keybd_event seems to trigger a sent message on NT4 */
11883 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11884 "wrong qstatus %08x\n", qstatus);
11885
11886 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11887 qstatus = GetQueueStatus(qs_all_input);
11888 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11889 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11890 "wrong qstatus %08x\n", qstatus);
11891
11892 InvalidateRect(info.hwnd, NULL, FALSE);
11893 qstatus = GetQueueStatus(qs_all_input);
11894 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11895 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11896 "wrong qstatus %08x\n", qstatus);
11897
11898 trace("signalling to send message\n");
11899 SetEvent(info.hevent[EV_SENDMSG]);
11900 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11901
11902 qstatus = GetQueueStatus(qs_all_input);
11903 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11904 "wrong qstatus %08x\n", qstatus);
11905
11906 msg.message = 0;
11907 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11908 if (ret && msg.message == WM_CHAR)
11909 {
11910 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11911 goto done;
11912 }
11913 ok(!ret,
11914 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11915 msg.message);
11916 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
11917 {
11918 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11919 goto done;
11920 }
11921 ok_sequence(WmUser, "WmUser", FALSE);
11922
11923 qstatus = GetQueueStatus(qs_all_input);
11924 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11925 "wrong qstatus %08x\n", qstatus);
11926
11927 trace("signalling to send message\n");
11928 SetEvent(info.hevent[EV_SENDMSG]);
11929 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11930
11931 qstatus = GetQueueStatus(qs_all_input);
11932 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11933 "wrong qstatus %08x\n", qstatus);
11934
11935 msg.message = 0;
11936 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11937 ok(!ret,
11938 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11939 msg.message);
11940 ok_sequence(WmUser, "WmUser", FALSE);
11941
11942 qstatus = GetQueueStatus(qs_all_input);
11943 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11944 "wrong qstatus %08x\n", qstatus);
11945
11946 msg.message = 0;
11947 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11948 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11949 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11950 ret, msg.message, msg.wParam);
11951 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11952
11953 qstatus = GetQueueStatus(qs_all_input);
11954 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11955 "wrong qstatus %08x\n", qstatus);
11956
11957 msg.message = 0;
11958 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11959 ok(!ret,
11960 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11961 msg.message);
11962 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11963
11964 qstatus = GetQueueStatus(qs_all_input);
11965 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11966 "wrong qstatus %08x\n", qstatus);
11967
11968 msg.message = 0;
11969 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11970 ok(ret && msg.message == WM_PAINT,
11971 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11972 DispatchMessageA(&msg);
11973 ok_sequence(WmPaint, "WmPaint", FALSE);
11974
11975 qstatus = GetQueueStatus(qs_all_input);
11976 ok(qstatus == MAKELONG(0, QS_KEY),
11977 "wrong qstatus %08x\n", qstatus);
11978
11979 msg.message = 0;
11980 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11981 ok(!ret,
11982 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11983 msg.message);
11984 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11985
11986 qstatus = GetQueueStatus(qs_all_input);
11987 ok(qstatus == MAKELONG(0, QS_KEY),
11988 "wrong qstatus %08x\n", qstatus);
11989
11990 trace("signalling to send message\n");
11991 SetEvent(info.hevent[EV_SENDMSG]);
11992 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11993
11994 qstatus = GetQueueStatus(qs_all_input);
11995 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11996 "wrong qstatus %08x\n", qstatus);
11997
11998 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11999
12000 qstatus = GetQueueStatus(qs_all_input);
12001 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12002 "wrong qstatus %08x\n", qstatus);
12003
12004 msg.message = 0;
12005 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12006 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12007 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12008 ret, msg.message, msg.wParam);
12009 ok_sequence(WmUser, "WmUser", FALSE);
12010
12011 qstatus = GetQueueStatus(qs_all_input);
12012 ok(qstatus == MAKELONG(0, QS_KEY),
12013 "wrong qstatus %08x\n", qstatus);
12014
12015 msg.message = 0;
12016 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12017 ok(!ret,
12018 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12019 msg.message);
12020 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12021
12022 qstatus = GetQueueStatus(qs_all_input);
12023 ok(qstatus == MAKELONG(0, QS_KEY),
12024 "wrong qstatus %08x\n", qstatus);
12025
12026 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12027
12028 qstatus = GetQueueStatus(qs_all_input);
12029 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
12030 "wrong qstatus %08x\n", qstatus);
12031
12032 trace("signalling to send message\n");
12033 SetEvent(info.hevent[EV_SENDMSG]);
12034 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12035
12036 qstatus = GetQueueStatus(qs_all_input);
12037 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12038 "wrong qstatus %08x\n", qstatus);
12039
12040 msg.message = 0;
12041 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
12042 ok(!ret,
12043 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12044 msg.message);
12045 ok_sequence(WmUser, "WmUser", FALSE);
12046
12047 qstatus = GetQueueStatus(qs_all_input);
12048 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12049 "wrong qstatus %08x\n", qstatus);
12050
12051 msg.message = 0;
12052 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12053 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12054 else /* workaround for a missing QS_RAWINPUT support */
12055 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
12056 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12057 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12058 ret, msg.message, msg.wParam);
12059 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12060
12061 qstatus = GetQueueStatus(qs_all_input);
12062 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12063 "wrong qstatus %08x\n", qstatus);
12064
12065 msg.message = 0;
12066 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12067 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12068 else /* workaround for a missing QS_RAWINPUT support */
12069 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
12070 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12071 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
12072 ret, msg.message, msg.wParam);
12073 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
12074
12075 qstatus = GetQueueStatus(qs_all_input);
12076 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12077 "wrong qstatus %08x\n", qstatus);
12078
12079 msg.message = 0;
12080 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
12081 ok(!ret,
12082 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12083 msg.message);
12084 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12085
12086 qstatus = GetQueueStatus(qs_all_input);
12087 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12088 "wrong qstatus %08x\n", qstatus);
12089
12090 msg.message = 0;
12091 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12092 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12093 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12094 ret, msg.message, msg.wParam);
12095 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12096
12097 qstatus = GetQueueStatus(qs_all_input);
12098 ok(qstatus == 0,
12099 "wrong qstatus %08x\n", qstatus);
12100
12101 msg.message = 0;
12102 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12103 ok(!ret,
12104 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12105 msg.message);
12106 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12107
12108 qstatus = GetQueueStatus(qs_all_input);
12109 ok(qstatus == 0,
12110 "wrong qstatus %08x\n", qstatus);
12111
12112 /* test whether presence of the quit flag in the queue affects
12113 * the queue state
12114 */
12115 PostQuitMessage(0x1234abcd);
12116
12117 qstatus = GetQueueStatus(qs_all_input);
12118 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12119 "wrong qstatus %08x\n", qstatus);
12120
12121 PostMessageA(info.hwnd, WM_USER, 0, 0);
12122
12123 qstatus = GetQueueStatus(qs_all_input);
12124 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12125 "wrong qstatus %08x\n", qstatus);
12126
12127 msg.message = 0;
12128 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12129 ok(ret && msg.message == WM_USER,
12130 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
12131 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12132
12133 qstatus = GetQueueStatus(qs_all_input);
12134 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12135 "wrong qstatus %08x\n", qstatus);
12136
12137 msg.message = 0;
12138 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12139 ok(ret && msg.message == WM_QUIT,
12140 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
12141 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
12142 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
12143 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12144
12145 qstatus = GetQueueStatus(qs_all_input);
12146 todo_wine {
12147 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12148 "wrong qstatus %08x\n", qstatus);
12149 }
12150
12151 msg.message = 0;
12152 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12153 ok(!ret,
12154 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12155 msg.message);
12156 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12157
12158 qstatus = GetQueueStatus(qs_all_input);
12159 ok(qstatus == 0,
12160 "wrong qstatus %08x\n", qstatus);
12161
12162 /* some GetMessage tests */
12163
12164 keybd_event('N', 0, 0, 0);
12165 qstatus = GetQueueStatus(qs_all_input);
12166 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12167
12168 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12169 qstatus = GetQueueStatus(qs_all_input);
12170 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12171
12172 if (qstatus)
12173 {
12174 ret = GetMessageA( &msg, 0, 0, 0 );
12175 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12176 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12177 ret, msg.message, msg.wParam);
12178 qstatus = GetQueueStatus(qs_all_input);
12179 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
12180 }
12181
12182 if (qstatus)
12183 {
12184 ret = GetMessageA( &msg, 0, 0, 0 );
12185 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12186 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12187 ret, msg.message, msg.wParam);
12188 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12189 qstatus = GetQueueStatus(qs_all_input);
12190 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12191 }
12192
12193 keybd_event('N', 0, 0, 0);
12194 qstatus = GetQueueStatus(qs_all_input);
12195 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12196
12197 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12198 qstatus = GetQueueStatus(qs_all_input);
12199 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12200
12201 if (qstatus & (QS_KEY << 16))
12202 {
12203 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12204 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12205 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12206 ret, msg.message, msg.wParam);
12207 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
12208 qstatus = GetQueueStatus(qs_all_input);
12209 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12210 }
12211
12212 if (qstatus)
12213 {
12214 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12215 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12216 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12217 ret, msg.message, msg.wParam);
12218 qstatus = GetQueueStatus(qs_all_input);
12219 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12220 }
12221
12222 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12223 qstatus = GetQueueStatus(qs_all_input);
12224 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12225
12226 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12227 qstatus = GetQueueStatus(qs_all_input);
12228 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12229
12230 trace("signalling to send message\n");
12231 SetEvent(info.hevent[EV_SENDMSG]);
12232 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12233 qstatus = GetQueueStatus(qs_all_input);
12234 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12235 "wrong qstatus %08x\n", qstatus);
12236
12237 if (qstatus & (QS_KEY << 16))
12238 {
12239 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12240 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12241 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12242 ret, msg.message, msg.wParam);
12243 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
12244 qstatus = GetQueueStatus(qs_all_input);
12245 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12246 }
12247
12248 if (qstatus)
12249 {
12250 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12251 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12252 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12253 ret, msg.message, msg.wParam);
12254 qstatus = GetQueueStatus(qs_all_input);
12255 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12256 }
12257
12258 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12259 ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE);
12260 ok(ret == TRUE, "wrong ret %d\n", ret);
12261 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12262 ret = GetMessageA(&msg, (HWND)-1, 0, 0);
12263 ok(ret == TRUE, "wrong ret %d\n", ret);
12264 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12265
12266 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12267 ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE);
12268 ok(ret == TRUE, "wrong ret %d\n", ret);
12269 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12270 ret = GetMessageA(&msg, (HWND)1, 0, 0);
12271 ok(ret == TRUE, "wrong ret %d\n", ret);
12272 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12273
12274 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12275 ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE);
12276 ok(ret == TRUE, "wrong ret %d\n", ret);
12277 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12278 ret = GetMessageA(&msg, (HWND)0xffff, 0, 0);
12279 ok(ret == TRUE, "wrong ret %d\n", ret);
12280 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12281
12282 done:
12283 trace("signalling to exit\n");
12284 SetEvent(info.hevent[EV_STOP]);
12285
12286 WaitForSingleObject(hthread, INFINITE);
12287
12288 CloseHandle(hthread);
12289 CloseHandle(info.hevent[0]);
12290 CloseHandle(info.hevent[1]);
12291 CloseHandle(info.hevent[2]);
12292
12293 DestroyWindow(info.hwnd);
12294 }
12295
12296 static void wait_move_event(HWND hwnd, int x, int y)
12297 {
12298 MSG msg;
12299 DWORD time;
12300 BOOL ret;
12301
12302 time = GetTickCount();
12303 while (GetTickCount() - time < 200) {
12304 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12305 if (ret && msg.pt.x > x && msg.pt.y > y) break;
12306 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
12307 else Sleep( GetTickCount() - time );
12308 }
12309 }
12310
12311 #define STEP 5
12312 static void test_PeekMessage2(void)
12313 {
12314 HWND hwnd;
12315 BOOL ret;
12316 MSG msg;
12317 UINT message;
12318 DWORD time1, time2, time3;
12319 int x1, y1, x2, y2, x3, y3;
12320 POINT pos;
12321
12322 time1 = time2 = time3 = 0;
12323 x1 = y1 = x2 = y2 = x3 = y3 = 0;
12324
12325 /* Initialise window and make sure it is ready for events */
12326 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
12327 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12328 assert(hwnd);
12329 trace("Window for test_PeekMessage2 %p\n", hwnd);
12330 ShowWindow(hwnd, SW_SHOW);
12331 UpdateWindow(hwnd);
12332 SetFocus(hwnd);
12333 GetCursorPos(&pos);
12334 SetCursorPos(100, 100);
12335 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
12336 flush_events();
12337
12338 /* Do initial mousemove, wait until we can see it
12339 and then do our test peek with PM_NOREMOVE. */
12340 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12341 wait_move_event(hwnd, 100-STEP, 100-STEP);
12342
12343 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12344 if (!ret)
12345 {
12346 skip( "queuing mouse events not supported\n" );
12347 goto done;
12348 }
12349 else
12350 {
12351 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12352 message = msg.message;
12353 time1 = msg.time;
12354 x1 = msg.pt.x;
12355 y1 = msg.pt.y;
12356 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12357 }
12358
12359 /* Allow time to advance a bit, and then simulate the user moving their
12360 * mouse around. After that we peek again with PM_NOREMOVE.
12361 * Although the previous mousemove message was never removed, the
12362 * mousemove we now peek should reflect the recent mouse movements
12363 * because the input queue will merge the move events. */
12364 Sleep(100);
12365 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12366 wait_move_event(hwnd, x1, y1);
12367
12368 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12369 ok(ret, "no message available\n");
12370 if (ret) {
12371 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12372 message = msg.message;
12373 time2 = msg.time;
12374 x2 = msg.pt.x;
12375 y2 = msg.pt.y;
12376 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12377 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12378 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12379 }
12380
12381 /* Have another go, to drive the point home */
12382 Sleep(100);
12383 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12384 wait_move_event(hwnd, x2, y2);
12385
12386 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12387 ok(ret, "no message available\n");
12388 if (ret) {
12389 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12390 message = msg.message;
12391 time3 = msg.time;
12392 x3 = msg.pt.x;
12393 y3 = msg.pt.y;
12394 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12395 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12396 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12397 }
12398
12399 done:
12400 DestroyWindow(hwnd);
12401 SetCursorPos(pos.x, pos.y);
12402 flush_events();
12403 }
12404
12405 static void test_PeekMessage3(void)
12406 {
12407 HWND hwnd;
12408 BOOL ret;
12409 MSG msg;
12410
12411 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12412 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12413 ok(hwnd != NULL, "expected hwnd != NULL\n");
12414 flush_events();
12415
12416 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12417 * were already seen. */
12418
12419 SetTimer(hwnd, 1, 0, NULL);
12420 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12421 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12422 PostMessageA(hwnd, WM_USER, 0, 0);
12423 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12424 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12425 ret = GetMessageA(&msg, NULL, 0, 0);
12426 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12427 ret = GetMessageA(&msg, NULL, 0, 0);
12428 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12429 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12430 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12431
12432 SetTimer(hwnd, 1, 0, NULL);
12433 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12434 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12435 PostMessageA(hwnd, WM_USER, 0, 0);
12436 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12437 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12438 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12439 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12440 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12441 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12442
12443 /* It doesn't matter if a message range is specified or not. */
12444
12445 SetTimer(hwnd, 1, 0, NULL);
12446 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12447 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12448 PostMessageA(hwnd, WM_USER, 0, 0);
12449 ret = GetMessageA(&msg, NULL, 0, 0);
12450 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12451 ret = GetMessageA(&msg, NULL, 0, 0);
12452 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12453 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12454 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12455
12456 /* But not if the post messages were added before the PeekMessage() call. */
12457
12458 PostMessageA(hwnd, WM_USER, 0, 0);
12459 SetTimer(hwnd, 1, 0, NULL);
12460 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12461 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12462 ret = GetMessageA(&msg, NULL, 0, 0);
12463 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12464 ret = GetMessageA(&msg, NULL, 0, 0);
12465 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12466 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12467 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12468
12469 /* More complicated test with multiple messages. */
12470
12471 PostMessageA(hwnd, WM_USER, 0, 0);
12472 SetTimer(hwnd, 1, 0, NULL);
12473 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12474 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12475 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12476 ret = GetMessageA(&msg, NULL, 0, 0);
12477 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12478 ret = GetMessageA(&msg, NULL, 0, 0);
12479 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12480 ret = GetMessageA(&msg, NULL, 0, 0);
12481 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12482 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12483 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12484
12485 /* Newer messages are still returned when specifying a message range. */
12486
12487 SetTimer(hwnd, 1, 0, NULL);
12488 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12489 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12490 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12491 PostMessageA(hwnd, WM_USER, 0, 0);
12492 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
12493 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12494 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE);
12495 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12496 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12497 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12498 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12499 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12500 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12501 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12502 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12503 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12504
12505 /* Also works for posted messages, but the situation is a bit different,
12506 * because both messages are in the same queue. */
12507
12508 PostMessageA(hwnd, WM_TIMER, 0, 0);
12509 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12510 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12511 PostMessageA(hwnd, WM_USER, 0, 0);
12512 ret = GetMessageA(&msg, NULL, 0, 0);
12513 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12514 ret = GetMessageA(&msg, NULL, 0, 0);
12515 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12516 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12517 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12518
12519 PostMessageA(hwnd, WM_USER, 0, 0);
12520 PostMessageA(hwnd, WM_TIMER, 0, 0);
12521 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12522 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12523 ret = GetMessageA(&msg, NULL, 0, 0);
12524 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12525 ret = GetMessageA(&msg, NULL, 0, 0);
12526 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12527 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12528 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12529
12530 DestroyWindow(hwnd);
12531 flush_events();
12532 }
12533
12534 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12535 {
12536 struct recvd_message msg;
12537
12538 if (ignore_message( message )) return 0;
12539
12540 msg.hwnd = hwnd;
12541 msg.message = message;
12542 msg.flags = sent|wparam|lparam;
12543 msg.wParam = wp;
12544 msg.lParam = lp;
12545 msg.descr = "dialog";
12546 add_message(&msg);
12547
12548 switch (message)
12549 {
12550 case WM_INITDIALOG:
12551 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12552 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12553 return 0;
12554
12555 case WM_GETDLGCODE:
12556 return 0;
12557
12558 case WM_USER:
12559 EndDialog(hwnd, 0);
12560 break;
12561 }
12562
12563 return 1;
12564 }
12565
12566 static const struct message WmQuitDialogSeq[] = {
12567 { HCBT_CREATEWND, hook },
12568 { WM_SETFONT, sent },
12569 { WM_INITDIALOG, sent },
12570 { WM_CHANGEUISTATE, sent|optional },
12571 { HCBT_DESTROYWND, hook },
12572 { 0x0090, sent|optional }, /* Vista */
12573 { WM_DESTROY, sent },
12574 { WM_NCDESTROY, sent },
12575 { 0 }
12576 };
12577
12578 static const struct message WmStopQuitSeq[] = {
12579 { WM_DWMNCRENDERINGCHANGED, posted|optional },
12580 { WM_CLOSE, posted },
12581 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12582 { 0 }
12583 };
12584
12585 static void test_quit_message(void)
12586 {
12587 MSG msg;
12588 BOOL ret;
12589
12590 /* test using PostQuitMessage */
12591 flush_events();
12592 PostQuitMessage(0xbeef);
12593
12594 msg.message = 0;
12595 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12596 ok(!ret, "got %x message\n", msg.message);
12597
12598 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12599 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12600 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12601 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12602
12603 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12604 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12605
12606 ret = GetMessageA(&msg, NULL, 0, 0);
12607 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12608 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12609
12610 /* note: WM_QUIT message received after WM_USER message */
12611 ret = GetMessageA(&msg, NULL, 0, 0);
12612 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12613 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12614 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12615
12616 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12617 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12618
12619 /* now test with PostThreadMessage - different behaviour! */
12620 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12621
12622 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12623 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12624 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12625 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12626
12627 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12628 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12629
12630 /* note: we receive the WM_QUIT message first this time */
12631 ret = GetMessageA(&msg, NULL, 0, 0);
12632 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12633 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12634 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12635
12636 ret = GetMessageA(&msg, NULL, 0, 0);
12637 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12638 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12639
12640 flush_events();
12641 flush_sequence();
12642 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12643 ok(ret == 1, "expected 1, got %d\n", ret);
12644 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12645 memset(&msg, 0xab, sizeof(msg));
12646 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12647 ok(ret, "PeekMessage failed\n");
12648 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12649 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12650 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12651
12652 /* Check what happens to a WM_QUIT message posted to a window that gets
12653 * destroyed.
12654 */
12655 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12656 0, 0, 100, 100, NULL, NULL, NULL, NULL);
12657 flush_sequence();
12658 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12659 {
12660 struct recvd_message rmsg;
12661 rmsg.hwnd = msg.hwnd;
12662 rmsg.message = msg.message;
12663 rmsg.flags = posted|wparam|lparam;
12664 rmsg.wParam = msg.wParam;
12665 rmsg.lParam = msg.lParam;
12666 rmsg.descr = "stop/quit";
12667 if (msg.message == WM_QUIT)
12668 /* The hwnd can only be checked here */
12669 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12670 add_message(&rmsg);
12671 DispatchMessageA(&msg);
12672 }
12673 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12674 }
12675
12676 static const struct message WmNotifySeq[] = {
12677 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12678 { 0 }
12679 };
12680
12681 static void test_notify_message(void)
12682 {
12683 HWND hwnd;
12684 BOOL ret;
12685 MSG msg;
12686
12687 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12688 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12689 ok(hwnd != 0, "Failed to create window\n");
12690 flush_events();
12691 flush_sequence();
12692
12693 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12694 ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12695 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12696
12697 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12698 ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12699 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12700
12701 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12702 ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12703 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12704
12705 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12706 ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12707 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12708
12709 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12710 ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12711 flush_events();
12712 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12713
12714 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12715 ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12716 flush_events();
12717 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12718
12719 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12720 ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12721 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12722 {
12723 msg.hwnd = hwnd;
12724 DispatchMessageA(&msg);
12725 }
12726 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12727
12728 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12729 ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12730 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12731 {
12732 msg.hwnd = hwnd;
12733 DispatchMessageA(&msg);
12734 }
12735 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12736
12737 DestroyWindow(hwnd);
12738 }
12739
12740 static const struct message WmMouseHoverSeq[] = {
12741 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12742 { WM_MOUSEACTIVATE, sent|optional },
12743 { WM_TIMER, sent|optional }, /* XP sends it */
12744 { WM_SYSTIMER, sent },
12745 { WM_MOUSEHOVER, sent|wparam, 0 },
12746 { 0 }
12747 };
12748
12749 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12750 {
12751 MSG msg;
12752 DWORD start_ticks, end_ticks;
12753
12754 start_ticks = GetTickCount();
12755 /* add some deviation (50%) to cover not expected delays */
12756 start_ticks += timeout / 2;
12757
12758 do
12759 {
12760 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12761 {
12762 /* Timer proc messages are not dispatched to the window proc,
12763 * and therefore not logged.
12764 */
12765 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12766 {
12767 struct recvd_message s_msg;
12768
12769 s_msg.hwnd = msg.hwnd;
12770 s_msg.message = msg.message;
12771 s_msg.flags = sent|wparam|lparam;
12772 s_msg.wParam = msg.wParam;
12773 s_msg.lParam = msg.lParam;
12774 s_msg.descr = "msg_loop";
12775 add_message(&s_msg);
12776 }
12777 DispatchMessageA(&msg);
12778 }
12779
12780 end_ticks = GetTickCount();
12781
12782 /* inject WM_MOUSEMOVE to see how it changes tracking */
12783 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
12784 {
12785 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12786 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12787
12788 inject_mouse_move = FALSE;
12789 }
12790 } while (start_ticks + timeout >= end_ticks);
12791 }
12792
12793 static void test_TrackMouseEvent(void)
12794 {
12795 TRACKMOUSEEVENT tme;
12796 BOOL ret;
12797 HWND hwnd, hchild;
12798 RECT rc_parent, rc_child;
12799 UINT default_hover_time, hover_width = 0, hover_height = 0;
12800
12801 #define track_hover(track_hwnd, track_hover_time) \
12802 tme.cbSize = sizeof(tme); \
12803 tme.dwFlags = TME_HOVER; \
12804 tme.hwndTrack = track_hwnd; \
12805 tme.dwHoverTime = track_hover_time; \
12806 SetLastError(0xdeadbeef); \
12807 ret = pTrackMouseEvent(&tme); \
12808 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
12809
12810 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
12811 tme.cbSize = sizeof(tme); \
12812 tme.dwFlags = TME_QUERY; \
12813 tme.hwndTrack = (HWND)0xdeadbeef; \
12814 tme.dwHoverTime = 0xdeadbeef; \
12815 SetLastError(0xdeadbeef); \
12816 ret = pTrackMouseEvent(&tme); \
12817 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
12818 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
12819 ok(tme.dwFlags == (expected_track_flags), \
12820 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
12821 ok(tme.hwndTrack == (expected_track_hwnd), \
12822 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
12823 ok(tme.dwHoverTime == (expected_hover_time), \
12824 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
12825
12826 #define track_hover_cancel(track_hwnd) \
12827 tme.cbSize = sizeof(tme); \
12828 tme.dwFlags = TME_HOVER | TME_CANCEL; \
12829 tme.hwndTrack = track_hwnd; \
12830 tme.dwHoverTime = 0xdeadbeef; \
12831 SetLastError(0xdeadbeef); \
12832 ret = pTrackMouseEvent(&tme); \
12833 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12834
12835 default_hover_time = 0xdeadbeef;
12836 SetLastError(0xdeadbeef);
12837 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12838 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12839 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12840 if (!ret) default_hover_time = 400;
12841 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12842
12843 SetLastError(0xdeadbeef);
12844 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12845 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12846 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12847 if (!ret) hover_width = 4;
12848 SetLastError(0xdeadbeef);
12849 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12850 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12851 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12852 if (!ret) hover_height = 4;
12853 trace("hover rect is %u x %d\n", hover_width, hover_height);
12854
12855 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12856 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12857 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12858 NULL, NULL, 0);
12859 assert(hwnd);
12860
12861 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12862 WS_CHILD | WS_BORDER | WS_VISIBLE,
12863 50, 50, 200, 200, hwnd,
12864 NULL, NULL, 0);
12865 assert(hchild);
12866
12867 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12868 flush_events();
12869 flush_sequence();
12870
12871 tme.cbSize = 0;
12872 tme.dwFlags = TME_QUERY;
12873 tme.hwndTrack = (HWND)0xdeadbeef;
12874 tme.dwHoverTime = 0xdeadbeef;
12875 SetLastError(0xdeadbeef);
12876 ret = pTrackMouseEvent(&tme);
12877 ok(!ret, "TrackMouseEvent should fail\n");
12878 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12879 "not expected error %u\n", GetLastError());
12880
12881 tme.cbSize = sizeof(tme);
12882 tme.dwFlags = TME_HOVER;
12883 tme.hwndTrack = (HWND)0xdeadbeef;
12884 tme.dwHoverTime = 0xdeadbeef;
12885 SetLastError(0xdeadbeef);
12886 ret = pTrackMouseEvent(&tme);
12887 ok(!ret, "TrackMouseEvent should fail\n");
12888 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12889 "not expected error %u\n", GetLastError());
12890
12891 tme.cbSize = sizeof(tme);
12892 tme.dwFlags = TME_HOVER | TME_CANCEL;
12893 tme.hwndTrack = (HWND)0xdeadbeef;
12894 tme.dwHoverTime = 0xdeadbeef;
12895 SetLastError(0xdeadbeef);
12896 ret = pTrackMouseEvent(&tme);
12897 ok(!ret, "TrackMouseEvent should fail\n");
12898 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12899 "not expected error %u\n", GetLastError());
12900
12901 GetWindowRect(hwnd, &rc_parent);
12902 GetWindowRect(hchild, &rc_child);
12903 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12904
12905 /* Process messages so that the system updates its internal current
12906 * window and hittest, otherwise TrackMouseEvent calls don't have any
12907 * effect.
12908 */
12909 flush_events();
12910 flush_sequence();
12911
12912 track_query(0, NULL, 0);
12913 track_hover(hchild, 0);
12914 track_query(0, NULL, 0);
12915
12916 flush_events();
12917 flush_sequence();
12918
12919 track_hover(hwnd, 0);
12920 tme.cbSize = sizeof(tme);
12921 tme.dwFlags = TME_QUERY;
12922 tme.hwndTrack = (HWND)0xdeadbeef;
12923 tme.dwHoverTime = 0xdeadbeef;
12924 SetLastError(0xdeadbeef);
12925 ret = pTrackMouseEvent(&tme);
12926 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12927 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12928 if (!tme.dwFlags)
12929 {
12930 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12931 DestroyWindow( hwnd );
12932 return;
12933 }
12934 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12935 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12936 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12937 tme.dwHoverTime, default_hover_time);
12938
12939 pump_msg_loop_timeout(default_hover_time, FALSE);
12940 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12941
12942 track_query(0, NULL, 0);
12943
12944 track_hover(hwnd, HOVER_DEFAULT);
12945 track_query(TME_HOVER, hwnd, default_hover_time);
12946
12947 Sleep(default_hover_time / 2);
12948 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12949 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12950
12951 track_query(TME_HOVER, hwnd, default_hover_time);
12952
12953 pump_msg_loop_timeout(default_hover_time, FALSE);
12954 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12955
12956 track_query(0, NULL, 0);
12957
12958 track_hover(hwnd, HOVER_DEFAULT);
12959 track_query(TME_HOVER, hwnd, default_hover_time);
12960
12961 pump_msg_loop_timeout(default_hover_time, TRUE);
12962 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12963
12964 track_query(0, NULL, 0);
12965
12966 track_hover(hwnd, HOVER_DEFAULT);
12967 track_query(TME_HOVER, hwnd, default_hover_time);
12968 track_hover_cancel(hwnd);
12969
12970 DestroyWindow(hwnd);
12971
12972 #undef track_hover
12973 #undef track_query
12974 #undef track_hover_cancel
12975 }
12976
12977
12978 static const struct message WmSetWindowRgn[] = {
12979 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12980 { WM_NCCALCSIZE, sent|wparam, 1 },
12981 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12982 { WM_GETTEXT, sent|defwinproc|optional },
12983 { WM_ERASEBKGND, sent|optional },
12984 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12985 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12986 { 0 }
12987 };
12988
12989 static const struct message WmSetWindowRgn_no_redraw[] = {
12990 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12991 { WM_NCCALCSIZE, sent|wparam, 1 },
12992 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12993 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12994 { 0 }
12995 };
12996
12997 static const struct message WmSetWindowRgn_clear[] = {
12998 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12999 { WM_NCCALCSIZE, sent|wparam, 1 },
13000 { WM_NCPAINT, sent|optional },
13001 { WM_GETTEXT, sent|defwinproc|optional },
13002 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
13003 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13004 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
13005 { WM_NCPAINT, sent|optional },
13006 { WM_GETTEXT, sent|defwinproc|optional },
13007 { WM_ERASEBKGND, sent|optional },
13008 { WM_WINDOWPOSCHANGING, sent|optional },
13009 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13010 { WM_NCPAINT, sent|optional },
13011 { WM_GETTEXT, sent|defwinproc|optional },
13012 { WM_ERASEBKGND, sent|optional },
13013 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13014 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13015 { WM_NCPAINT, sent|optional },
13016 { WM_GETTEXT, sent|defwinproc|optional },
13017 { WM_ERASEBKGND, sent|optional },
13018 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13019 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13020 { 0 }
13021 };
13022
13023 static void test_SetWindowRgn(void)
13024 {
13025 HRGN hrgn;
13026 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13027 100, 100, 200, 200, 0, 0, 0, NULL);
13028 ok( hwnd != 0, "Failed to create overlapped window\n" );
13029
13030 ShowWindow( hwnd, SW_SHOW );
13031 UpdateWindow( hwnd );
13032 flush_events();
13033 flush_sequence();
13034
13035 trace("testing SetWindowRgn\n");
13036 hrgn = CreateRectRgn( 0, 0, 150, 150 );
13037 SetWindowRgn( hwnd, hrgn, TRUE );
13038 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
13039
13040 hrgn = CreateRectRgn( 30, 30, 160, 160 );
13041 SetWindowRgn( hwnd, hrgn, FALSE );
13042 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
13043
13044 hrgn = CreateRectRgn( 0, 0, 180, 180 );
13045 SetWindowRgn( hwnd, hrgn, TRUE );
13046 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
13047
13048 SetWindowRgn( hwnd, 0, TRUE );
13049 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
13050
13051 DestroyWindow( hwnd );
13052 }
13053
13054 /*************************** ShowWindow() test ******************************/
13055 static const struct message WmShowNormal[] = {
13056 { WM_SHOWWINDOW, sent|wparam, 1 },
13057 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13058 { HCBT_ACTIVATE, hook },
13059 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13060 { HCBT_SETFOCUS, hook },
13061 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13062 { 0 }
13063 };
13064 static const struct message WmShow[] = {
13065 { WM_SHOWWINDOW, sent|wparam, 1 },
13066 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13067 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13068 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13069 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13070 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13071 { 0 }
13072 };
13073 static const struct message WmShowNoActivate_1[] = {
13074 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13075 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13076 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13077 { WM_MOVE, sent|defwinproc|optional },
13078 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13079 { 0 }
13080 };
13081 static const struct message WmShowNoActivate_2[] = {
13082 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13083 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13084 { HCBT_ACTIVATE, hook|optional },
13085 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13086 { HCBT_SETFOCUS, hook|optional },
13087 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13088 { WM_MOVE, sent|defwinproc },
13089 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13090 { HCBT_SETFOCUS, hook|optional },
13091 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13092 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13093 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13094 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13095 { 0 }
13096 };
13097 static const struct message WmShowNA_1[] = {
13098 { WM_SHOWWINDOW, sent|wparam, 1 },
13099 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13100 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13101 { 0 }
13102 };
13103 static const struct message WmShowNA_2[] = {
13104 { WM_SHOWWINDOW, sent|wparam, 1 },
13105 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13106 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13107 { 0 }
13108 };
13109 static const struct message WmRestore_1[] = {
13110 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13111 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13112 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13113 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13114 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13115 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13116 { WM_MOVE, sent|defwinproc },
13117 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13118 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13119 { 0 }
13120 };
13121 static const struct message WmRestore_2[] = {
13122 { WM_SHOWWINDOW, sent|wparam, 1 },
13123 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13124 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13125 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13126 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13127 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13128 { 0 }
13129 };
13130 static const struct message WmRestore_3[] = {
13131 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13132 { WM_GETMINMAXINFO, sent },
13133 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13134 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13135 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13136 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13137 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13138 { WM_MOVE, sent|defwinproc },
13139 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13140 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13141 { 0 }
13142 };
13143 static const struct message WmRestore_4[] = {
13144 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
13145 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13146 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13147 { WM_MOVE, sent|defwinproc|optional },
13148 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13149 { 0 }
13150 };
13151 static const struct message WmRestore_5[] = {
13152 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
13153 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13154 { HCBT_ACTIVATE, hook|optional },
13155 { HCBT_SETFOCUS, hook|optional },
13156 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13157 { WM_MOVE, sent|defwinproc|optional },
13158 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13159 { 0 }
13160 };
13161 static const struct message WmHide_1[] = {
13162 { WM_SHOWWINDOW, sent|wparam, 0 },
13163 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
13164 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
13165 { HCBT_ACTIVATE, hook|optional },
13166 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13167 { 0 }
13168 };
13169 static const struct message WmHide_2[] = {
13170 { WM_SHOWWINDOW, sent|wparam, 0 },
13171 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13172 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13173 { HCBT_ACTIVATE, hook|optional },
13174 { 0 }
13175 };
13176 static const struct message WmHide_3[] = {
13177 { WM_SHOWWINDOW, sent|wparam, 0 },
13178 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13179 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13180 { HCBT_SETFOCUS, hook|optional },
13181 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13182 { 0 }
13183 };
13184 static const struct message WmShowMinimized_1[] = {
13185 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13186 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13187 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13188 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13189 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13190 { WM_MOVE, sent|defwinproc },
13191 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13192 { 0 }
13193 };
13194 static const struct message WmMinimize_1[] = {
13195 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13196 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13197 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13198 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13199 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13200 { WM_MOVE, sent|defwinproc },
13201 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13202 { 0 }
13203 };
13204 static const struct message WmMinimize_2[] = {
13205 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13206 { HCBT_SETFOCUS, hook|optional },
13207 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13208 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13209 { WM_MOVE, sent|defwinproc },
13210 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13211 { 0 }
13212 };
13213 static const struct message WmMinimize_3[] = {
13214 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13215 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13216 { HCBT_ACTIVATE, hook|optional },
13217 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13218 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13219 { WM_MOVE, sent|defwinproc },
13220 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13221 { 0 }
13222 };
13223 static const struct message WmShowMinNoActivate[] = {
13224 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13225 { WM_WINDOWPOSCHANGING, sent },
13226 { WM_WINDOWPOSCHANGED, sent },
13227 { WM_MOVE, sent|defwinproc|optional },
13228 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13229 { 0 }
13230 };
13231 static const struct message WmMinMax_1[] = {
13232 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13233 { 0 }
13234 };
13235 static const struct message WmMinMax_2[] = {
13236 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13237 { WM_GETMINMAXINFO, sent|optional },
13238 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
13239 { HCBT_ACTIVATE, hook|optional },
13240 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13241 { HCBT_SETFOCUS, hook|optional },
13242 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13243 { WM_MOVE, sent|defwinproc|optional },
13244 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
13245 { HCBT_SETFOCUS, hook|optional },
13246 { 0 }
13247 };
13248 static const struct message WmMinMax_3[] = {
13249 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13250 { HCBT_SETFOCUS, hook|optional },
13251 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13252 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13253 { WM_MOVE, sent|defwinproc|optional },
13254 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13255 { 0 }
13256 };
13257 static const struct message WmMinMax_4[] = {
13258 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13259 { 0 }
13260 };
13261 static const struct message WmShowMaximized_1[] = {
13262 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13263 { WM_GETMINMAXINFO, sent },
13264 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13265 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13266 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13267 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13268 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13269 { WM_MOVE, sent|defwinproc },
13270 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13271 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13272 { 0 }
13273 };
13274 static const struct message WmShowMaximized_2[] = {
13275 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13276 { WM_GETMINMAXINFO, sent },
13277 { WM_WINDOWPOSCHANGING, sent|optional },
13278 { HCBT_ACTIVATE, hook|optional },
13279 { WM_WINDOWPOSCHANGED, sent|optional },
13280 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
13281 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
13282 { WM_WINDOWPOSCHANGING, sent|optional },
13283 { HCBT_SETFOCUS, hook|optional },
13284 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13285 { WM_MOVE, sent|defwinproc },
13286 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13287 { HCBT_SETFOCUS, hook|optional },
13288 { 0 }
13289 };
13290 static const struct message WmShowMaximized_3[] = {
13291 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13292 { WM_GETMINMAXINFO, sent|optional },
13293 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13294 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13295 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13296 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13297 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13298 { WM_MOVE, sent|defwinproc|optional },
13299 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13300 { 0 }
13301 };
13302
13303 static void test_ShowWindow(void)
13304 {
13305 /* ShowWindow commands in random order */
13306 static const struct
13307 {
13308 INT cmd; /* ShowWindow command */
13309 LPARAM ret; /* ShowWindow return value */
13310 DWORD style; /* window style after the command */
13311 const struct message *msg; /* message sequence the command produces */
13312 INT wp_cmd, wp_flags; /* window placement after the command */
13313 POINT wp_min, wp_max; /* window placement after the command */
13314 BOOL todo_msg; /* message sequence doesn't match what Wine does */
13315 } sw[] =
13316 {
13317 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
13318 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13319 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
13320 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13321 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
13322 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13323 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13324 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13325 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
13326 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13327 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
13328 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13329 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
13330 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13331 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13332 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13333 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
13334 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13335 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13336 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13337 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
13338 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13339 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
13340 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13341 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
13342 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13343 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13344 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13345 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
13346 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13347 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13348 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13349 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
13350 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13351 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13352 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13353 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13354 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13355 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13356 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13357 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13358 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13359 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13360 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13361 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13362 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13363 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13364 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13365 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13366 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13367 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13368 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13369 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13370 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13371 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13372 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13373 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13374 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13375 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13376 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13377 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13378 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13379 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13380 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13381 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13382 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13383 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13384 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13385 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13386 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13387 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13388 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13389 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13390 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13391 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13392 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13393 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13394 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13395 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13396 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13397 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13398 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13399 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13400 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13401 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13402 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13403 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13404 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13405 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13406 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13407 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13408 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13409 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13410 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13411 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13412 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13413 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13414 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13415 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13416 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13417 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13418 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13419 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13420 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13421 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13422 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13423 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13424 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13425 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13426 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13427 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13428 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13429 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13430 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13431 };
13432 HWND hwnd;
13433 DWORD style;
13434 LPARAM ret;
13435 INT i;
13436 WINDOWPLACEMENT wp;
13437 RECT win_rc, work_rc = {0, 0, 0, 0};
13438
13439 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13440 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13441 120, 120, 90, 90,
13442 0, 0, 0, NULL);
13443 assert(hwnd);
13444
13445 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13446 ok(style == 0, "expected style 0, got %08x\n", style);
13447
13448 flush_events();
13449 flush_sequence();
13450
13451 if (pGetMonitorInfoA && pMonitorFromPoint)
13452 {
13453 HMONITOR hmon;
13454 MONITORINFO mi;
13455 POINT pt = {0, 0};
13456
13457 SetLastError(0xdeadbeef);
13458 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13459 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13460
13461 mi.cbSize = sizeof(mi);
13462 SetLastError(0xdeadbeef);
13463 ret = pGetMonitorInfoA(hmon, &mi);
13464 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13465 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13466 wine_dbgstr_rect(&mi.rcWork));
13467 work_rc = mi.rcWork;
13468 }
13469
13470 GetWindowRect(hwnd, &win_rc);
13471 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13472
13473 wp.length = sizeof(wp);
13474 SetLastError(0xdeadbeaf);
13475 ret = GetWindowPlacement(hwnd, &wp);
13476 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13477 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13478 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13479 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13480 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13481 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13482 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13483 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13484 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13485 wine_dbgstr_rect(&wp.rcNormalPosition));
13486
13487 for (i = 0; i < ARRAY_SIZE(sw); i++)
13488 {
13489 static const char * const sw_cmd_name[13] =
13490 {
13491 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13492 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13493 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13494 "SW_NORMALNA" /* 0xCC */
13495 };
13496 char comment[64];
13497 INT idx; /* index into the above array of names */
13498
13499 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13500
13501 style = GetWindowLongA(hwnd, GWL_STYLE);
13502 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13503 ret = ShowWindow(hwnd, sw[i].cmd);
13504 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13505 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13506 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13507
13508 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13509 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13510
13511 wp.length = sizeof(wp);
13512 SetLastError(0xdeadbeaf);
13513 ret = GetWindowPlacement(hwnd, &wp);
13514 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13515 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13516 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13517
13518 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13519 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13520 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13521 {
13522 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13523 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13524 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13525 }
13526 else
13527 {
13528 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13529 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13530 }
13531
13532 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13533 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13534 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13535
13536 if (0) /* FIXME: Wine behaves completely different here */
13537 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13538 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13539 }
13540 DestroyWindow(hwnd);
13541 flush_events();
13542 }
13543
13544 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13545 {
13546 struct recvd_message msg;
13547
13548 if (ignore_message( message )) return 0;
13549
13550 msg.hwnd = hwnd;
13551 msg.message = message;
13552 msg.flags = sent|wparam|lparam;
13553 msg.wParam = wParam;
13554 msg.lParam = lParam;
13555 msg.descr = "dialog";
13556 add_message(&msg);
13557
13558 /* calling DefDlgProc leads to a recursion under XP */
13559
13560 switch (message)
13561 {
13562 case WM_INITDIALOG:
13563 return lParam;
13564
13565 case WM_GETDLGCODE:
13566 return 0;
13567 }
13568 return 1;
13569 }
13570
13571 static WNDPROC orig_edit_proc;
13572 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13573 {
13574 struct recvd_message msg;
13575
13576 if (ignore_message( message )) return 0;
13577
13578 msg.hwnd = hwnd;
13579 msg.message = message;
13580 msg.flags = sent|wparam|lparam;
13581 msg.wParam = wp;
13582 msg.lParam = lp;
13583 msg.descr = "edit";
13584 add_message(&msg);
13585
13586 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13587 }
13588
13589 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13590 {
13591 struct recvd_message msg;
13592
13593 if (ignore_message( message )) return 0;
13594
13595 msg.hwnd = hwnd;
13596 msg.message = message;
13597 msg.flags = sent|wparam|lparam|parent;
13598 msg.wParam = wParam;
13599 msg.lParam = lParam;
13600 msg.descr = "dialog";
13601 add_message(&msg);
13602
13603 if (message == WM_INITDIALOG)
13604 {
13605 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13606 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13607 }
13608
13609 return 1;
13610 }
13611
13612 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13613 {
13614 ok( 0, "should not be called since DefDlgProc is not used\n" );
13615 return 0;
13616 }
13617
13618 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13619 {
13620 struct recvd_message msg;
13621
13622 if (!ignore_message( message ))
13623 {
13624 msg.hwnd = hwnd;
13625 msg.message = message;
13626 msg.flags = sent|wparam|lparam|parent;
13627 msg.wParam = wParam;
13628 msg.lParam = lParam;
13629 msg.descr = "dialog";
13630 add_message(&msg);
13631 }
13632 if (message == WM_INITDIALOG)
13633 {
13634 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13635 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13636 return 1;
13637 }
13638 return DefWindowProcW( hwnd, message, wParam, lParam );
13639 }
13640
13641 static const struct message WmDefDlgSetFocus_1[] = {
13642 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13643 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13644 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13645 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13646 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13647 { HCBT_SETFOCUS, hook },
13648 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13649 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13650 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13651 { WM_SETFOCUS, sent|wparam, 0 },
13652 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13653 { WM_CTLCOLOREDIT, sent },
13654 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13655 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13656 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13657 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13658 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13659 { 0 }
13660 };
13661 static const struct message WmDefDlgSetFocus_2[] = {
13662 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13663 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13664 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13665 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13666 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13667 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13668 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13669 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13670 { 0 }
13671 };
13672 /* Creation of a dialog */
13673 static const struct message WmCreateDialogParamSeq_0[] = {
13674 { HCBT_CREATEWND, hook },
13675 { WM_NCCREATE, sent },
13676 { WM_NCCALCSIZE, sent|wparam, 0 },
13677 { WM_CREATE, sent },
13678 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13679 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13680 { WM_MOVE, sent },
13681 { WM_SETFONT, sent },
13682 { WM_INITDIALOG, sent },
13683 { WM_CHANGEUISTATE, sent|optional },
13684 { 0 }
13685 };
13686 /* Creation of a dialog */
13687 static const struct message WmCreateDialogParamSeq_1[] = {
13688 { HCBT_CREATEWND, hook },
13689 { WM_NCCREATE, sent },
13690 { WM_NCCALCSIZE, sent|wparam, 0 },
13691 { WM_CREATE, sent },
13692 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13693 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13694 { WM_MOVE, sent },
13695 { WM_SETFONT, sent },
13696 { WM_INITDIALOG, sent },
13697 { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13698 { HCBT_SETFOCUS, hook },
13699 { HCBT_ACTIVATE, hook },
13700 { WM_QUERYNEWPALETTE, sent|optional },
13701 { WM_PALETTEISCHANGING, sent|optional },
13702 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13703 { WM_ACTIVATEAPP, sent|wparam, 1 },
13704 { WM_NCACTIVATE, sent },
13705 { WM_ACTIVATE, sent|wparam, 1 },
13706 { WM_SETFOCUS, sent },
13707 { WM_CHANGEUISTATE, sent|optional },
13708 { 0 }
13709 };
13710 /* Creation of a dialog */
13711 static const struct message WmCreateDialogParamSeq_2[] = {
13712 { HCBT_CREATEWND, hook },
13713 { WM_NCCREATE, sent },
13714 { WM_NCCALCSIZE, sent|wparam, 0 },
13715 { WM_CREATE, sent },
13716 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13717 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13718 { WM_MOVE, sent },
13719 { WM_CHANGEUISTATE, sent|optional },
13720 { 0 }
13721 };
13722
13723 static const struct message WmCreateDialogParamSeq_3[] = {
13724 { HCBT_CREATEWND, hook },
13725 { WM_SETFONT, sent|parent },
13726 { WM_INITDIALOG, sent|parent },
13727 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13728 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13729 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13730 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13731 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13732 { HCBT_ACTIVATE, hook },
13733 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13734 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13735 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13736 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13737 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13738 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13739 { WM_NCACTIVATE, sent|parent },
13740 { WM_ACTIVATE, sent|parent|wparam, 1 },
13741 { WM_SETFOCUS, sent },
13742 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13743 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13744 { WM_USER, sent|parent },
13745 { WM_CHANGEUISTATE, sent|parent|optional },
13746 { 0 }
13747 };
13748
13749 static const struct message WmCreateDialogParamSeq_4[] = {
13750 { HCBT_CREATEWND, hook },
13751 { WM_NCCREATE, sent|parent },
13752 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13753 { WM_CREATE, sent|parent },
13754 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13755 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13756 { WM_MOVE, sent|parent },
13757 { WM_SETFONT, sent|parent },
13758 { WM_INITDIALOG, sent|parent },
13759 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13760 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13761 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13762 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13763 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13764 { HCBT_ACTIVATE, hook },
13765 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13766 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13767 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13768 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13769 { WM_NCACTIVATE, sent|parent },
13770 { WM_ACTIVATE, sent|parent|wparam, 1 },
13771 { HCBT_SETFOCUS, hook },
13772 { WM_SETFOCUS, sent|parent },
13773 { WM_KILLFOCUS, sent|parent },
13774 { WM_SETFOCUS, sent },
13775 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13776 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13777 { WM_USER, sent|parent },
13778 { WM_CHANGEUISTATE, sent|parent|optional },
13779 { WM_UPDATEUISTATE, sent|parent|optional },
13780 { WM_UPDATEUISTATE, sent|optional },
13781 { 0 }
13782 };
13783
13784 static void test_dialog_messages(void)
13785 {
13786 WNDCLASSA cls;
13787 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
13788 LRESULT ret;
13789
13790 #define set_selection(hctl, start, end) \
13791 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
13792 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
13793
13794 #define check_selection(hctl, start, end) \
13795 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
13796 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
13797
13798 subclass_edit();
13799
13800 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
13801 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13802 0, 0, 100, 100, 0, 0, 0, NULL);
13803 ok(hdlg != 0, "Failed to create custom dialog window\n");
13804
13805 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
13806 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13807 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
13808 ok(hedit1 != 0, "Failed to create edit control\n");
13809 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
13810 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13811 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
13812 ok(hedit2 != 0, "Failed to create edit control\n");
13813
13814 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
13815 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
13816
13817 hfocus = GetFocus();
13818 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13819
13820 SetFocus(hedit2);
13821 hfocus = GetFocus();
13822 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
13823
13824 check_selection(hedit1, 0, 0);
13825 check_selection(hedit2, 0, 0);
13826
13827 set_selection(hedit2, 0, -1);
13828 check_selection(hedit2, 0, 3);
13829
13830 SetFocus(0);
13831 hfocus = GetFocus();
13832 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13833
13834 flush_sequence();
13835 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13836 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13837 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
13838
13839 hfocus = GetFocus();
13840 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13841
13842 check_selection(hedit1, 0, 5);
13843 check_selection(hedit2, 0, 3);
13844
13845 flush_sequence();
13846 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13847 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13848 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
13849
13850 hfocus = GetFocus();
13851 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13852
13853 check_selection(hedit1, 0, 5);
13854 check_selection(hedit2, 0, 3);
13855
13856 EndDialog(hdlg, 0);
13857 DestroyWindow(hedit1);
13858 DestroyWindow(hedit2);
13859 DestroyWindow(hdlg);
13860 flush_sequence();
13861
13862 #undef set_selection
13863 #undef check_selection
13864
13865 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13866 cls.lpszClassName = "MyDialogClass";
13867 cls.hInstance = GetModuleHandleA(NULL);
13868 /* need a cast since a dlgproc is used as a wndproc */
13869 cls.lpfnWndProc = test_dlg_proc;
13870 if (!RegisterClassA(&cls)) assert(0);
13871
13872 SetFocus(0);
13873 flush_sequence();
13874 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13875 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13876 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
13877 hfocus = GetFocus();
13878 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13879 EndDialog(hdlg, 0);
13880 DestroyWindow(hdlg);
13881 flush_sequence();
13882
13883 SetFocus(0);
13884 flush_sequence();
13885 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
13886 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13887 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13888 hfocus = GetFocus();
13889 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13890 EndDialog(hdlg, 0);
13891 DestroyWindow(hdlg);
13892 flush_sequence();
13893
13894 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13895 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13896 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13897 EndDialog(hdlg, 0);
13898 DestroyWindow(hdlg);
13899 flush_sequence();
13900
13901 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13902 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13903 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13904 EndDialog(hdlg, 0);
13905 DestroyWindow(hdlg);
13906 flush_sequence();
13907
13908 UnregisterClassA( cls.lpszClassName, cls.hInstance );
13909 cls.lpfnWndProc = test_dlg_proc4;
13910 ok( RegisterClassA(&cls), "failed to register class again\n" );
13911 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13912 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13913 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13914 EndDialog(hdlg, 0);
13915 DestroyWindow(hdlg);
13916 flush_sequence();
13917
13918 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13919
13920 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13921 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13922 100, 100, 200, 200, 0, 0, 0, NULL);
13923 ok (parent != 0, "Failed to create parent window\n");
13924
13925 /* This child has no parent set. We will later call SetParent on it,
13926 * so that it will have a parent set, but no WS_CHILD style. */
13927 child = CreateWindowExA(0, "TestWindowClass", "Test child",
13928 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13929 100, 100, 200, 200, 0, 0, 0, NULL);
13930 ok (child != 0, "Failed to create child window\n");
13931
13932 /* This is a regular child window. When used as an owner, the other
13933 * child window will be used. */
13934 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13935 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13936 100, 100, 200, 200, child, 0, 0, NULL);
13937 ok (child2 != 0, "Failed to create child window\n");
13938
13939 SetParent(child, parent);
13940 SetFocus(child);
13941
13942 flush_sequence();
13943 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13944 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13945
13946 DestroyWindow(child2);
13947 DestroyWindow(child);
13948 DestroyWindow(parent);
13949 flush_sequence();
13950 }
13951
13952 static void test_enddialog_seq(HWND dialog, HWND owner)
13953 {
13954 const struct message seq[] = {
13955 { WM_ENABLE, sent },
13956 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13957 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13958 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13959 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13960 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13961 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13962 { WM_QUERYNEWPALETTE, sent|optional },
13963 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13964 { WM_GETTEXT, sent|optional|defwinproc },
13965 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13966 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13967 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13968 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13969 { 0 }
13970 };
13971
13972 flush_sequence();
13973 EndDialog(dialog, 0);
13974 ok_sequence(seq, "EndDialog", FALSE);
13975 }
13976
13977 static void test_enddialog_seq2(HWND dialog, HWND owner)
13978 {
13979 const struct message seq[] = {
13980 { WM_ENABLE, parent|sent },
13981 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13982 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13983 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13984 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13985 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13986 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13987 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13988 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13989 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13990 { 0 }
13991 };
13992
13993 flush_sequence();
13994 EndDialog(dialog, 0);
13995 ok_sequence(seq, "EndDialog2", FALSE);
13996 }
13997
13998 static void test_EndDialog(void)
13999 {
14000 HWND hparent, hother, hactive, hdlg, hchild;
14001 WNDCLASSA cls;
14002
14003 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14004 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14005 100, 100, 200, 200, 0, 0, 0, NULL);
14006 ok (hparent != 0, "Failed to create parent window\n");
14007
14008 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
14009 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14010 200, 100, 200, 200, 0, 0, 0, NULL);
14011 ok (hother != 0, "Failed to create parent window\n");
14012
14013 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
14014 cls.lpszClassName = "MyDialogClass";
14015 cls.hInstance = GetModuleHandleA(NULL);
14016 cls.lpfnWndProc = test_dlg_proc;
14017 if (!RegisterClassA(&cls)) assert(0);
14018
14019 flush_sequence();
14020 SetForegroundWindow(hother);
14021 hactive = GetForegroundWindow();
14022 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
14023
14024 /* create a dialog where the parent is disabled, this parent should be
14025 * enabled and receive focus when dialog exits */
14026 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
14027 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14028 SetForegroundWindow(hdlg);
14029 hactive = GetForegroundWindow();
14030 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
14031 EndDialog(hdlg, 0);
14032 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14033 hactive = GetForegroundWindow();
14034 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14035 DestroyWindow(hdlg);
14036 flush_sequence();
14037
14038 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
14039 EnableWindow(hparent, FALSE);
14040 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
14041 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
14042 0, 0, 100, 100, hparent, 0, 0, NULL);
14043 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14044 flush_sequence();
14045 SetForegroundWindow(hother);
14046 flush_sequence();
14047 hactive = GetForegroundWindow();
14048 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
14049 hactive = GetActiveWindow();
14050 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
14051 EndDialog(hdlg, 0);
14052 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14053 hactive = GetForegroundWindow();
14054 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14055 DestroyWindow(hdlg);
14056 flush_sequence();
14057
14058 DestroyWindow( hparent );
14059
14060 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14061 WS_POPUP | WS_VISIBLE | WS_DISABLED,
14062 100, 100, 200, 200, 0, 0, 0, NULL);
14063 ok (hparent != 0, "Failed to create parent window\n");
14064
14065 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
14066 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14067 0, 0, 0, 0, 0, 0, 0, NULL);
14068 ok (hchild != 0, "Failed to create child window\n");
14069
14070 SetParent(hchild, hparent);
14071
14072 flush_sequence();
14073 SetForegroundWindow(hother);
14074 hactive = GetForegroundWindow();
14075 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14076
14077 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14078 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14079
14080 SetForegroundWindow(hdlg);
14081 test_enddialog_seq(hdlg, hchild);
14082
14083 hactive = GetForegroundWindow();
14084 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14085
14086 DestroyWindow(hdlg);
14087
14088 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
14089 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
14090
14091 SetForegroundWindow(hother);
14092 hactive = GetForegroundWindow();
14093 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14094
14095 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14096 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14097
14098 SetForegroundWindow(hdlg);
14099 test_enddialog_seq2(hdlg, hparent);
14100
14101 hactive = GetForegroundWindow();
14102 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14103 DestroyWindow(hdlg);
14104 DestroyWindow(hchild);
14105 DestroyWindow(hparent);
14106 DestroyWindow(hother);
14107 flush_sequence();
14108
14109 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14110 }
14111
14112 static void test_nullCallback(void)
14113 {
14114 HWND hwnd;
14115
14116 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
14117 100, 100, 200, 200, 0, 0, 0, NULL);
14118 ok (hwnd != 0, "Failed to create overlapped window\n");
14119
14120 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
14121 flush_events();
14122 DestroyWindow(hwnd);
14123 }
14124
14125 /* SetActiveWindow( 0 ) hwnd visible */
14126 static const struct message SetActiveWindowSeq0[] =
14127 {
14128 { HCBT_ACTIVATE, hook|optional },
14129 { WM_NCACTIVATE, sent|wparam, 0 },
14130 { WM_GETTEXT, sent|defwinproc|optional },
14131 { WM_ACTIVATE, sent|wparam, 0 },
14132 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14133 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14134 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14135 { WM_KILLFOCUS, sent|optional },
14136 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14137 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14138 { WM_NCACTIVATE, sent|wparam|optional, 1 },
14139 { WM_GETTEXT, sent|defwinproc|optional },
14140 { WM_ACTIVATE, sent|wparam|optional, 1 },
14141 { HCBT_SETFOCUS, hook|optional },
14142 { WM_KILLFOCUS, sent|defwinproc|optional },
14143 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14144 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14145 { WM_IME_SETCONTEXT, sent|optional },
14146 { WM_IME_SETCONTEXT, sent|optional },
14147 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14148 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14149 { WM_SETFOCUS, sent|defwinproc|optional },
14150 { WM_GETTEXT, sent|optional },
14151 { 0 }
14152 };
14153 /* SetActiveWindow( hwnd ) hwnd visible */
14154 static const struct message SetActiveWindowSeq1[] =
14155 {
14156 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14157 { 0 }
14158 };
14159 /* SetActiveWindow( popup ) hwnd visible, popup visible */
14160 static const struct message SetActiveWindowSeq2[] =
14161 {
14162 { HCBT_ACTIVATE, hook },
14163 { WM_NCACTIVATE, sent|wparam, 0 },
14164 { WM_GETTEXT, sent|defwinproc|optional },
14165 { WM_ACTIVATE, sent|wparam, 0 },
14166 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14167 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14168 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14169 { WM_NCPAINT, sent|optional },
14170 { WM_GETTEXT, sent|defwinproc|optional },
14171 { WM_ERASEBKGND, sent|optional },
14172 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14173 { WM_NCACTIVATE, sent|wparam, 1 },
14174 { WM_GETTEXT, sent|defwinproc|optional },
14175 { WM_ACTIVATE, sent|wparam, 1 },
14176 { HCBT_SETFOCUS, hook },
14177 { WM_KILLFOCUS, sent|defwinproc },
14178 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14179 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14180 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14181 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14182 { WM_SETFOCUS, sent|defwinproc },
14183 { WM_GETTEXT, sent|optional },
14184 { 0 }
14185 };
14186
14187 /* SetActiveWindow( hwnd ) hwnd not visible */
14188 static const struct message SetActiveWindowSeq3[] =
14189 {
14190 { HCBT_ACTIVATE, hook },
14191 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14192 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14193 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14194 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14195 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14196 { WM_ACTIVATEAPP, sent|wparam, 1 },
14197 { WM_ACTIVATEAPP, sent|wparam, 1 },
14198 { WM_NCACTIVATE, sent|wparam, 1 },
14199 { WM_ACTIVATE, sent|wparam, 1 },
14200 { HCBT_SETFOCUS, hook },
14201 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14202 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14203 { WM_SETFOCUS, sent|defwinproc },
14204 { 0 }
14205 };
14206 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
14207 static const struct message SetActiveWindowSeq4[] =
14208 {
14209 { HCBT_ACTIVATE, hook },
14210 { WM_NCACTIVATE, sent|wparam, 0 },
14211 { WM_GETTEXT, sent|defwinproc|optional },
14212 { WM_ACTIVATE, sent|wparam, 0 },
14213 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14214 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14215 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14216 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14217 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14218 { WM_NCACTIVATE, sent|wparam, 1 },
14219 { WM_GETTEXT, sent|defwinproc|optional },
14220 { WM_ACTIVATE, sent|wparam, 1 },
14221 { HCBT_SETFOCUS, hook },
14222 { WM_KILLFOCUS, sent|defwinproc },
14223 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14224 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14225 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14226 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14227 { WM_SETFOCUS, sent|defwinproc },
14228 { 0 }
14229 };
14230
14231
14232 static void test_SetActiveWindow(void)
14233 {
14234 HWND hwnd, popup, ret;
14235
14236 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14237 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14238 100, 100, 200, 200, 0, 0, 0, NULL);
14239
14240 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14241 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
14242 100, 100, 200, 200, hwnd, 0, 0, NULL);
14243
14244 ok(hwnd != 0, "Failed to create overlapped window\n");
14245 ok(popup != 0, "Failed to create popup window\n");
14246 SetForegroundWindow( popup );
14247 flush_sequence();
14248
14249 trace("SetActiveWindow(0)\n");
14250 ret = SetActiveWindow(0);
14251 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
14252 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
14253 flush_sequence();
14254
14255 trace("SetActiveWindow(hwnd), hwnd visible\n");
14256 ret = SetActiveWindow(hwnd);
14257 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
14258 flush_sequence();
14259
14260 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
14261 ret = SetActiveWindow(popup);
14262 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
14263 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
14264 flush_sequence();
14265
14266 ShowWindow(hwnd, SW_HIDE);
14267 ShowWindow(popup, SW_HIDE);
14268 flush_sequence();
14269
14270 trace("SetActiveWindow(hwnd), hwnd not visible\n");
14271 ret = SetActiveWindow(hwnd);
14272 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
14273 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
14274 flush_sequence();
14275
14276 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
14277 ret = SetActiveWindow(popup);
14278 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
14279 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
14280 flush_sequence();
14281
14282 trace("done\n");
14283
14284 DestroyWindow(hwnd);
14285 }
14286
14287 static const struct message SetForegroundWindowSeq[] =
14288 {
14289 { WM_NCACTIVATE, sent|wparam, 0 },
14290 { WM_GETTEXT, sent|defwinproc|optional },
14291 { WM_ACTIVATE, sent|wparam, 0 },
14292 { WM_ACTIVATEAPP, sent|wparam, 0 },
14293 { WM_KILLFOCUS, sent },
14294 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
14295 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
14296 { 0 }
14297 };
14298
14299 static void test_SetForegroundWindow(void)
14300 {
14301 HWND hwnd;
14302
14303 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
14304 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14305 100, 100, 200, 200, 0, 0, 0, NULL);
14306 ok (hwnd != 0, "Failed to create overlapped window\n");
14307 SetForegroundWindow( hwnd );
14308 flush_sequence();
14309
14310 trace("SetForegroundWindow( 0 )\n");
14311 SetForegroundWindow( 0 );
14312 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
14313 trace("SetForegroundWindow( GetDesktopWindow() )\n");
14314 SetForegroundWindow( GetDesktopWindow() );
14315 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
14316 "foreground top level window", FALSE);
14317 trace("done\n");
14318
14319 DestroyWindow(hwnd);
14320 }
14321
14322 static DWORD get_input_codepage( void )
14323 {
14324 DWORD cp;
14325 int ret;
14326 HKL hkl = GetKeyboardLayout( 0 );
14327
14328 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
14329 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
14330 if (!ret) cp = CP_ACP;
14331 return cp;
14332 }
14333
14334 static void test_dbcs_wm_char(void)
14335 {
14336 BYTE dbch[2];
14337 WCHAR wch, bad_wch;
14338 HWND hwnd, hwnd2;
14339 MSG msg;
14340 DWORD time;
14341 POINT pt;
14342 DWORD_PTR res;
14343 CPINFOEXA cpinfo;
14344 UINT i, j, k;
14345 struct message wmCharSeq[2];
14346 BOOL ret;
14347 DWORD cp = get_input_codepage();
14348
14349 if (!pGetCPInfoExA)
14350 {
14351 win_skip("GetCPInfoExA is not available\n");
14352 return;
14353 }
14354
14355 pGetCPInfoExA( cp, 0, &cpinfo );
14356 if (cpinfo.MaxCharSize != 2)
14357 {
14358 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14359 return;
14360 }
14361
14362 dbch[0] = dbch[1] = 0;
14363 wch = 0;
14364 bad_wch = cpinfo.UnicodeDefaultChar;
14365 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14366 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14367 for (k = 128; k <= 255; k++)
14368 {
14369 char str[2];
14370 WCHAR wstr[2];
14371 str[0] = j;
14372 str[1] = k;
14373 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14374 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14375 (BYTE)str[0] == j && (BYTE)str[1] == k &&
14376 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14377 {
14378 dbch[0] = j;
14379 dbch[1] = k;
14380 wch = wstr[0];
14381 break;
14382 }
14383 }
14384
14385 if (!wch)
14386 {
14387 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14388 return;
14389 }
14390 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14391 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14392
14393 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14394 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14395 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14396 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14397 ok (hwnd != 0, "Failed to create overlapped window\n");
14398 ok (hwnd2 != 0, "Failed to create overlapped window\n");
14399 flush_sequence();
14400
14401 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14402 wmCharSeq[0].message = WM_CHAR;
14403 wmCharSeq[0].flags = sent|wparam;
14404 wmCharSeq[0].wParam = wch;
14405
14406 /* posted message */
14407 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14408 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14409 ok( !ret, "got message %x\n", msg.message );
14410 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14411 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14412 ok( ret, "no message\n" );
14413 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14414 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14415 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14416 ok( !ret, "got message %x\n", msg.message );
14417
14418 /* posted thread message */
14419 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14420 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14421 ok( !ret, "got message %x\n", msg.message );
14422 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14423 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14424 ok( ret, "no message\n" );
14425 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14426 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14427 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14428 ok( !ret, "got message %x\n", msg.message );
14429
14430 /* sent message */
14431 flush_sequence();
14432 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14433 ok_sequence( WmEmptySeq, "no messages", FALSE );
14434 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14435 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14436 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14437 ok( !ret, "got message %x\n", msg.message );
14438
14439 /* sent message with timeout */
14440 flush_sequence();
14441 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14442 ok_sequence( WmEmptySeq, "no messages", FALSE );
14443 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14444 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14445 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14446 ok( !ret, "got message %x\n", msg.message );
14447
14448 /* sent message with timeout and callback */
14449 flush_sequence();
14450 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14451 ok_sequence( WmEmptySeq, "no messages", FALSE );
14452 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14453 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14454 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14455 ok( !ret, "got message %x\n", msg.message );
14456
14457 /* sent message with callback */
14458 flush_sequence();
14459 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14460 ok_sequence( WmEmptySeq, "no messages", FALSE );
14461 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14462 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14463 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14464 ok( !ret, "got message %x\n", msg.message );
14465
14466 /* direct window proc call */
14467 flush_sequence();
14468 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14469 ok_sequence( WmEmptySeq, "no messages", FALSE );
14470 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14471 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14472
14473 /* dispatch message */
14474 msg.hwnd = hwnd;
14475 msg.message = WM_CHAR;
14476 msg.wParam = dbch[0];
14477 msg.lParam = 0;
14478 DispatchMessageA( &msg );
14479 ok_sequence( WmEmptySeq, "no messages", FALSE );
14480 msg.wParam = dbch[1];
14481 DispatchMessageA( &msg );
14482 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14483
14484 /* window handle is irrelevant */
14485 flush_sequence();
14486 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14487 ok_sequence( WmEmptySeq, "no messages", FALSE );
14488 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14489 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14490 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14491 ok( !ret, "got message %x\n", msg.message );
14492
14493 /* interleaved post and send */
14494 flush_sequence();
14495 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14496 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14497 ok_sequence( WmEmptySeq, "no messages", FALSE );
14498 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14499 ok( !ret, "got message %x\n", msg.message );
14500 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14501 ok_sequence( WmEmptySeq, "no messages", FALSE );
14502 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14503 ok( ret, "no message\n" );
14504 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14505 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14506 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14507 ok( !ret, "got message %x\n", msg.message );
14508 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14509 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14510 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14511 ok( !ret, "got message %x\n", msg.message );
14512
14513 /* interleaved sent message and winproc */
14514 flush_sequence();
14515 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14516 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14517 ok_sequence( WmEmptySeq, "no messages", FALSE );
14518 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14519 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14520 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14521 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14522
14523 /* interleaved winproc and dispatch */
14524 msg.hwnd = hwnd;
14525 msg.message = WM_CHAR;
14526 msg.wParam = dbch[0];
14527 msg.lParam = 0;
14528 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14529 DispatchMessageA( &msg );
14530 ok_sequence( WmEmptySeq, "no messages", FALSE );
14531 msg.wParam = dbch[1];
14532 DispatchMessageA( &msg );
14533 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14534 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14535 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14536
14537 /* interleaved sends */
14538 flush_sequence();
14539 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14540 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14541 ok_sequence( WmEmptySeq, "no messages", FALSE );
14542 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14543 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14544 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14545 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14546
14547 /* dbcs WM_CHAR */
14548 flush_sequence();
14549 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14550 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14551 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14552 ok( !ret, "got message %x\n", msg.message );
14553
14554 /* other char messages are not magic */
14555 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14556 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14557 ok( ret, "no message\n" );
14558 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14559 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14560 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14561 ok( !ret, "got message %x\n", msg.message );
14562 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14563 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14564 ok( ret, "no message\n" );
14565 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14566 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14567 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14568 ok( !ret, "got message %x\n", msg.message );
14569
14570 /* test retrieving messages */
14571
14572 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14573 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14574 ok( ret, "no message\n" );
14575 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14576 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14577 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14578 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14579 ok( ret, "no message\n" );
14580 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14581 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14582 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14583 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14584 ok( !ret, "got message %x\n", msg.message );
14585
14586 /* message filters */
14587 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14588 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14589 ok( ret, "no message\n" );
14590 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14591 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14592 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14593 /* message id is filtered, hwnd is not */
14594 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14595 ok( !ret, "no message\n" );
14596 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14597 ok( ret, "no message\n" );
14598 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14599 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14600 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14601 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14602 ok( !ret, "got message %x\n", msg.message );
14603
14604 /* mixing GetMessage and PostMessage */
14605 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14606 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14607 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14608 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14609 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14610 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14611 time = msg.time;
14612 pt = msg.pt;
14613 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14614 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14615 ok( ret, "no message\n" );
14616 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14617 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14618 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14619 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14620 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14621 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 );
14622 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14623 ok( !ret, "got message %x\n", msg.message );
14624
14625 /* without PM_REMOVE */
14626 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14627 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14628 ok( ret, "no message\n" );
14629 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14630 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14631 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14632 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14633 ok( ret, "no message\n" );
14634 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14635 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14636 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14637 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14638 ok( ret, "no message\n" );
14639 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14640 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14641 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14642 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14643 ok( ret, "no message\n" );
14644 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14645 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14646 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14647 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14648 ok( !ret, "got message %x\n", msg.message );
14649
14650 DestroyWindow(hwnd);
14651 DestroyWindow(hwnd2);
14652 }
14653
14654 static void test_unicode_wm_char(void)
14655 {
14656 HWND hwnd;
14657 MSG msg;
14658 struct message seq[2];
14659 HKL hkl_orig, hkl_greek;
14660 DWORD cp;
14661 LCID thread_locale;
14662
14663 hkl_orig = GetKeyboardLayout( 0 );
14664 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14665 if (cp != 1252)
14666 {
14667 skip( "Default codepage %d\n", cp );
14668 return;
14669 }
14670
14671 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14672 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14673 {
14674 skip( "Unable to load Greek keyboard layout\n" );
14675 return;
14676 }
14677
14678 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14679 100, 100, 200, 200, 0, 0, 0, NULL );
14680 flush_sequence();
14681
14682 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14683
14684 while (GetMessageW( &msg, hwnd, 0, 0 ))
14685 {
14686 if (!ignore_message( msg.message )) break;
14687 }
14688
14689 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14690 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14691 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14692 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14693
14694 DispatchMessageW( &msg );
14695
14696 memset( seq, 0, sizeof(seq) );
14697 seq[0].message = WM_CHAR;
14698 seq[0].flags = sent|wparam;
14699 seq[0].wParam = 0x3b1;
14700
14701 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14702
14703 flush_sequence();
14704
14705 /* greek alpha -> 'a' in cp1252 */
14706 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14707
14708 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14709 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14710 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14711 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
14712 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14713
14714 DispatchMessageA( &msg );
14715
14716 seq[0].wParam = 0x61;
14717 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14718
14719 thread_locale = GetThreadLocale();
14720 ActivateKeyboardLayout( hkl_greek, 0 );
14721 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14722 thread_locale, GetThreadLocale() );
14723
14724 flush_sequence();
14725
14726 /* greek alpha -> 0xe1 in cp1253 */
14727 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14728
14729 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14730 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14731 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14732 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14733 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14734
14735 DispatchMessageA( &msg );
14736
14737 seq[0].wParam = 0x3b1;
14738 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14739
14740 DestroyWindow( hwnd );
14741 ActivateKeyboardLayout( hkl_orig, 0 );
14742 UnloadKeyboardLayout( hkl_greek );
14743 }
14744
14745 #define ID_LISTBOX 0x000f
14746
14747 static const struct message wm_lb_setcursel_0[] =
14748 {
14749 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14750 { WM_CTLCOLORLISTBOX, sent|parent },
14751 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14752 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14753 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14754 { 0 }
14755 };
14756 static const struct message wm_lb_setcursel_1[] =
14757 {
14758 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14759 { WM_CTLCOLORLISTBOX, sent|parent },
14760 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14761 { WM_CTLCOLORLISTBOX, sent|parent },
14762 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14763 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14764 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14765 { 0 }
14766 };
14767 static const struct message wm_lb_setcursel_2[] =
14768 {
14769 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14770 { WM_CTLCOLORLISTBOX, sent|parent },
14771 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14772 { WM_CTLCOLORLISTBOX, sent|parent },
14773 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14774 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14775 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14776 { 0 }
14777 };
14778 static const struct message wm_lb_click_0[] =
14779 {
14780 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
14781 { HCBT_SETFOCUS, hook },
14782 { WM_KILLFOCUS, sent|parent },
14783 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
14784 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14785 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14786 { WM_SETFOCUS, sent|defwinproc },
14787
14788 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
14789 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
14790 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14791 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
14792 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14793
14794 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
14795 { WM_CTLCOLORLISTBOX, sent|parent },
14796 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
14797 { WM_CTLCOLORLISTBOX, sent|parent },
14798 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14799 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
14800
14801 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14802 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14803
14804 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
14805 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14806 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
14807 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
14808 { 0 }
14809 };
14810 static const struct message wm_lb_deletestring[] =
14811 {
14812 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14813 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14814 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14815 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14816 { 0 }
14817 };
14818 static const struct message wm_lb_deletestring_reset[] =
14819 {
14820 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14821 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
14822 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14823 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14824 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14825 { 0 }
14826 };
14827 static const struct message wm_lb_addstring[] =
14828 {
14829 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14830 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14831 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14832 { 0 }
14833 };
14834 static const struct message wm_lb_addstring_ownerdraw[] =
14835 {
14836 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14837 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14838 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14839 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14840 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14841 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14842 { 0 }
14843 };
14844 static const struct message wm_lb_addstring_sort_ownerdraw[] =
14845 {
14846 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14847 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14848 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14849 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
14850 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14851 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14852 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
14853 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
14854 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14855 { 0 }
14856 };
14857
14858 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
14859
14860 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
14861
14862 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14863 {
14864 static LONG defwndproc_counter = 0;
14865 LRESULT ret;
14866 struct recvd_message msg;
14867
14868 /* do not log painting messages */
14869 if (message != WM_PAINT &&
14870 message != WM_NCPAINT &&
14871 message != WM_SYNCPAINT &&
14872 message != WM_ERASEBKGND &&
14873 message != WM_NCHITTEST &&
14874 message != WM_GETTEXT &&
14875 !ignore_message( message ))
14876 {
14877 msg.hwnd = hwnd;
14878 msg.message = message;
14879 msg.flags = sent|wparam|lparam;
14880 if (defwndproc_counter) msg.flags |= defwinproc;
14881 msg.wParam = wp;
14882 if (message == LB_ADDSTRING)
14883 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
14884 else
14885 msg.lParam = lp;
14886 msg.descr = "listbox";
14887 add_message(&msg);
14888 }
14889
14890 defwndproc_counter++;
14891 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
14892 defwndproc_counter--;
14893
14894 return ret;
14895 }
14896
14897 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
14898 int caret_index, int top_index, int line)
14899 {
14900 LRESULT ret;
14901
14902 /* calling an orig proc helps to avoid unnecessary message logging */
14903 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14904 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14905 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14906 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14907 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14908 ok_(__FILE__, line)(ret == caret_index ||
14909 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
14910 "expected caret index %d, got %ld\n", caret_index, ret);
14911 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14912 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14913 }
14914
14915 static void test_listbox_messages(void)
14916 {
14917 HWND parent, listbox;
14918 LRESULT ret;
14919
14920 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14921 100, 100, 200, 200, 0, 0, 0, NULL);
14922 /* with LBS_HASSTRINGS */
14923 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14924 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14925 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14926 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14927
14928 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14929
14930 flush_sequence();
14931
14932 log_all_parent_messages++;
14933
14934 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14935 ok(ret == 0, "expected 0, got %ld\n", ret);
14936 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14937 ok(ret == 1, "expected 1, got %ld\n", ret);
14938 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14939 ok(ret == 2, "expected 2, got %ld\n", ret);
14940
14941 ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
14942 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14943
14944 flush_sequence();
14945
14946 trace("selecting item 0\n");
14947 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14948 ok(ret == 0, "expected 0, got %ld\n", ret);
14949 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14950 check_lb_state(listbox, 3, 0, 0, 0);
14951 flush_sequence();
14952
14953 trace("selecting item 1\n");
14954 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14955 ok(ret == 1, "expected 1, got %ld\n", ret);
14956 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14957 check_lb_state(listbox, 3, 1, 1, 0);
14958
14959 trace("selecting item 2\n");
14960 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14961 ok(ret == 2, "expected 2, got %ld\n", ret);
14962 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14963 check_lb_state(listbox, 3, 2, 2, 0);
14964
14965 trace("clicking on item 0\n");
14966 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14967 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14968 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14969 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14970 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14971 check_lb_state(listbox, 3, 0, 0, 0);
14972 flush_sequence();
14973
14974 trace("deleting item 0\n");
14975 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14976 ok(ret == 2, "expected 2, got %ld\n", ret);
14977 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14978 check_lb_state(listbox, 2, -1, 0, 0);
14979 flush_sequence();
14980
14981 trace("deleting item 0\n");
14982 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14983 ok(ret == 1, "expected 1, got %ld\n", ret);
14984 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14985 check_lb_state(listbox, 1, -1, 0, 0);
14986 flush_sequence();
14987
14988 trace("deleting item 0\n");
14989 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14990 ok(ret == 0, "expected 0, got %ld\n", ret);
14991 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14992 check_lb_state(listbox, 0, -1, 0, 0);
14993 flush_sequence();
14994
14995 trace("deleting item 0\n");
14996 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14997 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14998 check_lb_state(listbox, 0, -1, 0, 0);
14999 flush_sequence();
15000
15001 log_all_parent_messages--;
15002
15003 DestroyWindow(listbox);
15004
15005 /* with LBS_SORT and without LBS_HASSTRINGS */
15006 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15007 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
15008 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15009 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15010
15011 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15012
15013 flush_sequence();
15014
15015 log_all_parent_messages++;
15016
15017 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15018 ok(ret == 0, "expected 0, got %ld\n", ret);
15019 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15020 ok(ret == 1, "expected 1, got %ld\n", ret);
15021 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15022 ok(ret == 2, "expected 2, got %ld\n", ret);
15023
15024 ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
15025 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15026
15027 log_all_parent_messages--;
15028
15029 DestroyWindow(listbox);
15030
15031 /* with LBS_HASSTRINGS */
15032 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15033 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
15034 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15035 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15036
15037 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15038
15039 flush_sequence();
15040
15041 log_all_parent_messages++;
15042
15043 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15044 ok(ret == 0, "expected 0, got %ld\n", ret);
15045 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15046 ok(ret == 1, "expected 1, got %ld\n", ret);
15047 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15048 ok(ret == 2, "expected 2, got %ld\n", ret);
15049
15050 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15051 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15052
15053 log_all_parent_messages--;
15054
15055 DestroyWindow(listbox);
15056
15057 /* with LBS_HASSTRINGS and LBS_SORT */
15058 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15059 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
15060 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15061 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15062
15063 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15064
15065 flush_sequence();
15066
15067 log_all_parent_messages++;
15068
15069 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15070 ok(ret == 0, "expected 0, got %ld\n", ret);
15071 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15072 ok(ret == 0, "expected 0, got %ld\n", ret);
15073 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15074 ok(ret == 1, "expected 1, got %ld\n", ret);
15075
15076 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15077 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15078
15079 log_all_parent_messages--;
15080
15081 DestroyWindow(listbox);
15082 DestroyWindow(parent);
15083 }
15084
15085 /*************************** Menu test ******************************/
15086 static const struct message wm_popup_menu_1[] =
15087 {
15088 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15089 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15090 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
15091 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
15092 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
15093 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
15094 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15095 { WM_INITMENU, sent|lparam, 0, 0 },
15096 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
15097 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
15098 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
15099 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
15100 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
15101 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15102 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
15103 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
15104 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15105 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15106 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15107 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
15108 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15109 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15110 { 0 }
15111 };
15112 static const struct message wm_popup_menu_2[] =
15113 {
15114 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15115 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15116 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15117 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15118 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15119 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15120 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15121 { WM_INITMENU, sent|lparam, 0, 0 },
15122 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15123 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15124 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15125 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15126 { HCBT_CREATEWND, hook },
15127 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15128 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15129 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15130 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15131 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15132 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15133 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15134 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15135 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15136 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15137 { HCBT_DESTROYWND, hook },
15138 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15139 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15140 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15141 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15142 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15143 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
15144 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15145 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15146 { 0 }
15147 };
15148 static const struct message wm_popup_menu_3[] =
15149 {
15150 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15151 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15152 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15153 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15154 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15155 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15156 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15157 { WM_INITMENU, sent|lparam, 0, 0 },
15158 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15159 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15160 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15161 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15162 { HCBT_CREATEWND, hook },
15163 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15164 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15165 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15166 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15167 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15168 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15169 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15170 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15171 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15172 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15173 { HCBT_DESTROYWND, hook },
15174 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15175 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15176 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15177 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15178 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15179 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
15180 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15181 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15182 { 0 }
15183 };
15184
15185 static const struct message wm_single_menu_item[] =
15186 {
15187 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15188 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15189 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
15190 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
15191 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
15192 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
15193 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15194 { WM_INITMENU, sent|lparam, 0, 0 },
15195 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
15196 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15197 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15198 { WM_MENUCOMMAND, sent },
15199 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
15200 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
15201 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
15202 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
15203
15204 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
15205 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
15206 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
15207 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
15208 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
15209 { 0 }
15210 };
15211
15212 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15213 {
15214 if (message == WM_ENTERIDLE ||
15215 message == WM_INITMENU ||
15216 message == WM_INITMENUPOPUP ||
15217 message == WM_MENUSELECT ||
15218 message == WM_PARENTNOTIFY ||
15219 message == WM_ENTERMENULOOP ||
15220 message == WM_EXITMENULOOP ||
15221 message == WM_UNINITMENUPOPUP ||
15222 message == WM_KEYDOWN ||
15223 message == WM_KEYUP ||
15224 message == WM_CHAR ||
15225 message == WM_SYSKEYDOWN ||
15226 message == WM_SYSKEYUP ||
15227 message == WM_SYSCHAR ||
15228 message == WM_COMMAND ||
15229 message == WM_MENUCOMMAND)
15230 {
15231 struct recvd_message msg;
15232
15233 msg.hwnd = hwnd;
15234 msg.message = message;
15235 msg.flags = sent|wparam|lparam;
15236 msg.wParam = wp;
15237 msg.lParam = lp;
15238 msg.descr = "parent_menu_proc";
15239 add_message(&msg);
15240 }
15241
15242 return DefWindowProcA(hwnd, message, wp, lp);
15243 }
15244
15245 static void set_menu_style(HMENU hmenu, DWORD style)
15246 {
15247 MENUINFO mi;
15248 BOOL ret;
15249
15250 mi.cbSize = sizeof(mi);
15251 mi.fMask = MIM_STYLE;
15252 mi.dwStyle = style;
15253 SetLastError(0xdeadbeef);
15254 ret = pSetMenuInfo(hmenu, &mi);
15255 ok(ret, "SetMenuInfo error %u\n", GetLastError());
15256 }
15257
15258 static DWORD get_menu_style(HMENU hmenu)
15259 {
15260 MENUINFO mi;
15261 BOOL ret;
15262
15263 mi.cbSize = sizeof(mi);
15264 mi.fMask = MIM_STYLE;
15265 mi.dwStyle = 0;
15266 SetLastError(0xdeadbeef);
15267 ret = pGetMenuInfo(hmenu, &mi);
15268 ok(ret, "GetMenuInfo error %u\n", GetLastError());
15269
15270 return mi.dwStyle;
15271 }
15272
15273 static void test_menu_messages(void)
15274 {
15275 MSG msg;
15276 WNDCLASSA cls;
15277 HMENU hmenu, hmenu_popup;
15278 HWND hwnd;
15279 DWORD style;
15280
15281 if (!pGetMenuInfo || !pSetMenuInfo)
15282 {
15283 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
15284 return;
15285 }
15286 cls.style = 0;
15287 cls.lpfnWndProc = parent_menu_proc;
15288 cls.cbClsExtra = 0;
15289 cls.cbWndExtra = 0;
15290 cls.hInstance = GetModuleHandleA(0);
15291 cls.hIcon = 0;
15292 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15293 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15294 cls.lpszMenuName = NULL;
15295 cls.lpszClassName = "TestMenuClass";
15296 UnregisterClassA(cls.lpszClassName, cls.hInstance);
15297 if (!RegisterClassA(&cls)) assert(0);
15298
15299 SetLastError(0xdeadbeef);
15300 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15301 100, 100, 200, 200, 0, 0, 0, NULL);
15302 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
15303
15304 SetLastError(0xdeadbeef);
15305 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
15306 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
15307
15308 SetMenu(hwnd, hmenu);
15309 SetForegroundWindow( hwnd );
15310 flush_events();
15311
15312 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
15313 style = get_menu_style(hmenu);
15314 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15315
15316 hmenu_popup = GetSubMenu(hmenu, 0);
15317 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15318 style = get_menu_style(hmenu_popup);
15319 ok(style == 0, "expected 0, got %u\n", style);
15320
15321 hmenu_popup = GetSubMenu(hmenu_popup, 0);
15322 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15323 style = get_menu_style(hmenu_popup);
15324 ok(style == 0, "expected 0, got %u\n", style);
15325
15326 /* Alt+E, Enter */
15327 trace("testing a popup menu command\n");
15328 flush_sequence();
15329 keybd_event(VK_MENU, 0, 0, 0);
15330 keybd_event('E', 0, 0, 0);
15331 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
15332 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15333 keybd_event(VK_RETURN, 0, 0, 0);
15334 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15335 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15336 {
15337 TranslateMessage(&msg);
15338 DispatchMessageA(&msg);
15339 }
15340 if (!sequence_cnt) /* we didn't get any message */
15341 {
15342 skip( "queuing key events not supported\n" );
15343 goto done;
15344 }
15345 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
15346 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
15347 {
15348 win_skip( "menu tracking through VK_MENU not supported\n" );
15349 goto done;
15350 }
15351 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
15352
15353 /* Alt+F, Right, Enter */
15354 trace("testing submenu of a popup menu command\n");
15355 flush_sequence();
15356 keybd_event(VK_MENU, 0, 0, 0);
15357 keybd_event('F', 0, 0, 0);
15358 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15359 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15360 keybd_event(VK_RIGHT, 0, 0, 0);
15361 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15362 keybd_event(VK_RETURN, 0, 0, 0);
15363 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15364 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15365 {
15366 TranslateMessage(&msg);
15367 DispatchMessageA(&msg);
15368 }
15369 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
15370
15371 trace("testing single menu item command\n");
15372 flush_sequence();
15373 keybd_event(VK_MENU, 0, 0, 0);
15374 keybd_event('Q', 0, 0, 0);
15375 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
15376 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15377 keybd_event(VK_ESCAPE, 0, 0, 0);
15378 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
15379 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15380 {
15381 TranslateMessage(&msg);
15382 DispatchMessageA(&msg);
15383 }
15384 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
15385
15386 set_menu_style(hmenu, 0);
15387 style = get_menu_style(hmenu);
15388 ok(style == 0, "expected 0, got %u\n", style);
15389
15390 hmenu_popup = GetSubMenu(hmenu, 0);
15391 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15392 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
15393 style = get_menu_style(hmenu_popup);
15394 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15395
15396 hmenu_popup = GetSubMenu(hmenu_popup, 0);
15397 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15398 style = get_menu_style(hmenu_popup);
15399 ok(style == 0, "expected 0, got %u\n", style);
15400
15401 /* Alt+F, Right, Enter */
15402 trace("testing submenu of a popup menu command\n");
15403 flush_sequence();
15404 keybd_event(VK_MENU, 0, 0, 0);
15405 keybd_event('F', 0, 0, 0);
15406 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15407 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15408 keybd_event(VK_RIGHT, 0, 0, 0);
15409 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15410 keybd_event(VK_RETURN, 0, 0, 0);
15411 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15412 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15413 {
15414 TranslateMessage(&msg);
15415 DispatchMessageA(&msg);
15416 }
15417 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15418
15419 done:
15420 DestroyWindow(hwnd);
15421 DestroyMenu(hmenu);
15422 }
15423
15424
15425 static void test_paintingloop(void)
15426 {
15427 HWND hwnd;
15428
15429 paint_loop_done = FALSE;
15430 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15431 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15432 100, 100, 100, 100, 0, 0, 0, NULL );
15433 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15434 ShowWindow(hwnd,SW_NORMAL);
15435 SetFocus(hwnd);
15436
15437 while (!paint_loop_done)
15438 {
15439 MSG msg;
15440 if (PeekMessageA(&msg, 0, 0, 0, 1))
15441 {
15442 TranslateMessage(&msg);
15443 DispatchMessageA(&msg);
15444 }
15445 }
15446 DestroyWindow(hwnd);
15447 }
15448
15449 static const struct message NCRBUTTONDOWNSeq[] =
15450 {
15451 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15452 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15453 { WM_CAPTURECHANGED, sent },
15454 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15455 { 0 }
15456 };
15457
15458 static const struct message NCXBUTTONUPSeq1[] =
15459 {
15460 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15461 { 0 }
15462 };
15463
15464 static const struct message NCXBUTTONUPSeq2[] =
15465 {
15466 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15467 { 0 }
15468 };
15469
15470 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */
15471 static const struct message WmRestoreMinimizedOverlappedSeq[] =
15472 {
15473 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
15474 { HCBT_MINMAX, hook },
15475 { WM_QUERYOPEN, sent },
15476 { WM_GETTEXT, sent|optional },
15477 { WM_NCACTIVATE, sent|optional },
15478 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15479 { WM_WINDOWPOSCHANGED, sent|optional },
15480 { WM_WINDOWPOSCHANGING, sent|optional },
15481 { WM_GETMINMAXINFO, sent|defwinproc },
15482 { WM_NCCALCSIZE, sent|optional },
15483 { WM_NCPAINT, sent|optional },
15484 { WM_GETTEXT, sent|defwinproc|optional },
15485 { WM_ERASEBKGND, sent|optional },
15486 { WM_WINDOWPOSCHANGED, sent|optional },
15487 { HCBT_ACTIVATE, hook },
15488 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
15489 { WM_ACTIVATEAPP, sent|wparam, TRUE },
15490 { WM_NCACTIVATE, sent|wparam, TRUE },
15491 { WM_GETTEXT, sent|defwinproc|optional },
15492 { WM_ACTIVATE, sent|wparam, TRUE },
15493 { HCBT_SETFOCUS, hook },
15494 { WM_SETFOCUS, sent|defwinproc },
15495 { WM_NCPAINT, sent },
15496 { WM_GETTEXT, sent|defwinproc|optional },
15497 { WM_ERASEBKGND, sent },
15498 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED },
15499 { WM_MOVE, sent|defwinproc },
15500 { WM_SIZE, sent|defwinproc },
15501 { WM_NCCALCSIZE, sent|optional },
15502 { WM_NCPAINT, sent|optional },
15503 { WM_ERASEBKGND, sent|optional },
15504 { WM_ACTIVATE, sent|wparam, TRUE },
15505 { WM_SYNCPAINT, sent|optional },
15506 { WM_PAINT, sent },
15507 { 0 }
15508 };
15509
15510 static struct message WmContextMenuSeq[] = {
15511 { WM_CONTEXTMENU, sent|wparam, 0 }, /* wparams set in the code */
15512 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
15513 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
15514 { 0 }
15515 };
15516
15517 struct rbuttonup_thread_data
15518 {
15519 HWND hwnd;
15520 HANDLE wndproc_finished;
15521 };
15522
15523 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15524 {
15525 struct rbuttonup_thread_data *data = arg;
15526 DWORD ret;
15527
15528 ret = WaitForSingleObject( data->wndproc_finished, 500 );
15529 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15530 if( ret == WAIT_OBJECT_0 ) return 0;
15531
15532 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15533 return 0;
15534 }
15535
15536 static void test_defwinproc(void)
15537 {
15538 HWND hwnd, child[3];
15539 MSG msg;
15540 BOOL gotwmquit = FALSE;
15541 POINT pos;
15542 RECT rect;
15543 INT x, y;
15544 LRESULT res;
15545 struct rbuttonup_thread_data data;
15546 char buffA[64];
15547 HANDLE thread;
15548
15549 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15550 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15551 assert(hwnd);
15552 flush_events();
15553
15554 buffA[0] = 0;
15555 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15556 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15557
15558 /* Zero high word of the lParam */
15559 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15560 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15561
15562 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15563 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15564
15565 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15566 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15567
15568 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15569 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15570
15571 ShowWindow(hwnd, SW_MINIMIZE);
15572 flush_events();
15573 flush_sequence();
15574
15575 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
15576 flush_events();
15577 ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE);
15578 flush_sequence();
15579
15580 child[0] = CreateWindowExA(0, "TestWindowClass", "1st child",
15581 WS_VISIBLE | WS_CHILD, 0,0,500,100, hwnd, 0, 0, NULL);
15582 child[1] = CreateWindowExA(0, "TestWindowClass", "2nd child",
15583 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[0], 0, 0, NULL);
15584 child[2] = CreateWindowExA(0, "TestWindowClass", "3rd child",
15585 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[1], 0, 0, NULL);
15586 flush_events();
15587 flush_sequence();
15588 test_context_menu = TRUE;
15589 DefWindowProcA(child[2], WM_CONTEXTMENU, 0xcafe, 0);
15590 test_context_menu = FALSE;
15591 WmContextMenuSeq[0].wParam = (WPARAM)child[2];
15592 WmContextMenuSeq[1].wParam = (WPARAM)child[1];
15593 WmContextMenuSeq[2].wParam = (WPARAM)child[0];
15594 ok_sequence(WmContextMenuSeq, "DefWindowProcA(WM_CONTEXTMENU)", FALSE);
15595 DestroyWindow(child[0]);
15596
15597 GetCursorPos(&pos);
15598 GetWindowRect(hwnd, &rect);
15599 x = (rect.left+rect.right) / 2;
15600 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15601 SetCursorPos(x, y);
15602 flush_events();
15603 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15604 ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15605
15606 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15607 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15608 flush_events();
15609
15610 flush_sequence();
15611 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15612 /* workaround for missing support for clicking on window frame */
15613 data.hwnd = hwnd;
15614 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15615 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15616
15617 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15618 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15619
15620 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15621 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15622 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15623
15624 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15625 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15626 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15627
15628 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15629 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15630 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15631
15632 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15633 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15634 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15635
15636 SetEvent( data.wndproc_finished );
15637 WaitForSingleObject( thread, 1000 );
15638 CloseHandle( data.wndproc_finished );
15639 CloseHandle( thread );
15640
15641 SetCursorPos(pos.x, pos.y);
15642
15643 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15644 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15645 if( msg.message == WM_QUIT) gotwmquit = TRUE;
15646 DispatchMessageA( &msg );
15647 }
15648 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15649 DestroyWindow( hwnd);
15650 }
15651
15652 static void test_desktop_winproc(void)
15653 {
15654 HINSTANCE instance = GetModuleHandleA(NULL);
15655 RECT rect, default_rect;
15656 WNDPROC desktop_proc;
15657 char buffer[256];
15658 WNDCLASSA cls;
15659 LRESULT res;
15660 HWND hwnd;
15661 BOOL ret;
15662
15663 ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls);
15664 ok(ret, "Failed to get desktop class.\n");
15665 desktop_proc = cls.lpfnWndProc;
15666
15667 memset(&cls, 0, sizeof(cls));
15668 cls.lpfnWndProc = desktop_proc;
15669 cls.hInstance = instance;
15670 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15671 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15672 cls.lpszClassName = "TestDesktopClass";
15673 ret = !!RegisterClassA(&cls);
15674 ok(ret, "Failed to register class.\n");
15675
15676 hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc",
15677 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL);
15678 if (!hwnd) /* win2003 */
15679 {
15680 skip("Failed to create window with desktop window procedure.\n");
15681 goto out_unregister;
15682 }
15683
15684 memset(&cls, 0, sizeof(cls));
15685 ret = GetClassInfoA(instance, "TestDesktopClass", &cls);
15686 ok(ret, "Failed to get class info.\n");
15687 ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc);
15688
15689 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15690 todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer);
15691
15692 res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test");
15693 ok(res == TRUE, "Failed to set text, %ld.\n", res);
15694 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15695 ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer);
15696
15697 SetRect(&default_rect, 0, 0, 100, 100);
15698 res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect);
15699 ok(!res, "Got unexpected result %ld.\n", res);
15700
15701 SetRect(&rect, 0, 0, 100, 100);
15702 res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
15703 ok(!res, "Got unexpected result %ld.\n", res);
15704 todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n",
15705 wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect));
15706
15707 DestroyWindow(hwnd);
15708
15709 out_unregister:
15710 UnregisterClassA("TestDesktopClass", instance);
15711 }
15712
15713 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
15714 static void clear_clipboard_(int line, HWND hWnd)
15715 {
15716 BOOL succ;
15717 succ = OpenClipboard(hWnd);
15718 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15719 succ = EmptyClipboard();
15720 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15721 succ = CloseClipboard();
15722 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15723 }
15724
15725 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
15726 static void expect_HWND_(int line, HWND expected, HWND got)
15727 {
15728 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
15729 }
15730
15731 static WNDPROC pOldViewerProc;
15732
15733 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
15734 {
15735 static BOOL recursion_guard;
15736
15737 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
15738 {
15739 recursion_guard = TRUE;
15740 clear_clipboard(hWnd);
15741 recursion_guard = FALSE;
15742 }
15743 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
15744 }
15745
15746 static void test_clipboard_viewers(void)
15747 {
15748 static struct message wm_change_cb_chain[] =
15749 {
15750 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
15751 { 0 }
15752 };
15753 static const struct message wm_clipboard_destroyed[] =
15754 {
15755 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15756 { 0 }
15757 };
15758 static struct message wm_clipboard_changed[] =
15759 {
15760 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15761 { 0 }
15762 };
15763 static struct message wm_clipboard_changed_and_owned[] =
15764 {
15765 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15766 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15767 { 0 }
15768 };
15769
15770 HINSTANCE hInst = GetModuleHandleA(NULL);
15771 HWND hWnd1, hWnd2, hWnd3;
15772 HWND hOrigViewer;
15773 HWND hRet;
15774
15775 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
15776 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15777 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15778 GetDesktopWindow(), NULL, hInst, NULL);
15779 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
15780 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15781 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15782 GetDesktopWindow(), NULL, hInst, NULL);
15783 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
15784 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15785 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15786 GetDesktopWindow(), NULL, hInst, NULL);
15787 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
15788 assert(hWnd1 && hWnd2 && hWnd3);
15789
15790 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
15791 flush_sequence();
15792
15793 /* Test getting the clipboard viewer and setting the viewer to NULL. */
15794 hOrigViewer = GetClipboardViewer();
15795 hRet = SetClipboardViewer(NULL);
15796 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
15797 expect_HWND(hOrigViewer, hRet);
15798 expect_HWND(NULL, GetClipboardViewer());
15799
15800 /* Test registering hWnd1 as a viewer. */
15801 hRet = SetClipboardViewer(hWnd1);
15802 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15803 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
15804 expect_HWND(NULL, hRet);
15805 expect_HWND(hWnd1, GetClipboardViewer());
15806
15807 /* Test that changing the clipboard actually refreshes the registered viewer. */
15808 clear_clipboard(hWnd1);
15809 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15810 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
15811
15812 /* Again, but with different owner. */
15813 clear_clipboard(hWnd2);
15814 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
15815 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
15816
15817 /* Test re-registering same window. */
15818 hRet = SetClipboardViewer(hWnd1);
15819 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15820 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
15821 expect_HWND(hWnd1, hRet);
15822 expect_HWND(hWnd1, GetClipboardViewer());
15823
15824 /* Test ChangeClipboardChain. */
15825 ChangeClipboardChain(hWnd2, hWnd3);
15826 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15827 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
15828 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
15829 expect_HWND(hWnd1, GetClipboardViewer());
15830
15831 ChangeClipboardChain(hWnd2, NULL);
15832 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15833 wm_change_cb_chain[0].lParam = 0;
15834 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
15835 expect_HWND(hWnd1, GetClipboardViewer());
15836
15837 ChangeClipboardChain(NULL, hWnd2);
15838 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
15839 expect_HWND(hWnd1, GetClipboardViewer());
15840
15841 /* Actually change clipboard viewer with ChangeClipboardChain. */
15842 ChangeClipboardChain(hWnd1, hWnd2);
15843 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
15844 expect_HWND(hWnd2, GetClipboardViewer());
15845
15846 /* Test that no refresh messages are sent when viewer has unregistered. */
15847 clear_clipboard(hWnd2);
15848 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
15849
15850 /* Register hWnd1 again. */
15851 ChangeClipboardChain(hWnd2, hWnd1);
15852 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
15853 expect_HWND(hWnd1, GetClipboardViewer());
15854
15855 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
15856 * changes the clipboard. When this happens, the system shouldn't send
15857 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
15858 */
15859 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
15860 clear_clipboard(hWnd2);
15861 /* The clipboard owner is changed in recursive_viewer_proc: */
15862 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
15863 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
15864
15865 /* Test unregistering. */
15866 ChangeClipboardChain(hWnd1, NULL);
15867 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
15868 expect_HWND(NULL, GetClipboardViewer());
15869
15870 clear_clipboard(hWnd1);
15871 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
15872
15873 DestroyWindow(hWnd1);
15874 DestroyWindow(hWnd2);
15875 DestroyWindow(hWnd3);
15876 SetClipboardViewer(hOrigViewer);
15877 }
15878
15879 static void test_PostMessage(void)
15880 {
15881 static const struct
15882 {
15883 HWND hwnd;
15884 BOOL ret;
15885 } data[] =
15886 {
15887 { HWND_TOP /* 0 */, TRUE },
15888 { HWND_BROADCAST, TRUE },
15889 { HWND_BOTTOM, TRUE },
15890 { HWND_TOPMOST, TRUE },
15891 { HWND_NOTOPMOST, FALSE },
15892 { HWND_MESSAGE, FALSE },
15893 { (HWND)0xdeadbeef, FALSE }
15894 };
15895 int i;
15896 HWND hwnd;
15897 BOOL ret;
15898 MSG msg;
15899 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
15900
15901 SetLastError(0xdeadbeef);
15902 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
15903 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
15904 {
15905 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
15906 return;
15907 }
15908 assert(hwnd);
15909
15910 flush_events();
15911
15912 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
15913 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
15914
15915 for (i = 0; i < ARRAY_SIZE(data); i++)
15916 {
15917 memset(&msg, 0xab, sizeof(msg));
15918 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
15919 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
15920 if (data[i].ret)
15921 {
15922 if (data[i].hwnd)
15923 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
15924 msg.wParam == 0x5678 && msg.lParam == 0x1234,
15925 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
15926 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
15927 else
15928 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
15929 msg.wParam == 0x1234 && msg.lParam == 0x5678,
15930 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
15931 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
15932 }
15933 }
15934
15935 DestroyWindow(hwnd);
15936 flush_events();
15937 }
15938
15939 static LPARAM g_broadcast_lparam;
15940 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15941 {
15942 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
15943
15944 if (wParam == 0xbaadbeef)
15945 g_broadcast_lparam = wParam;
15946 else
15947 g_broadcast_lparam = 0;
15948
15949 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
15950 }
15951
15952 static void test_broadcast(void)
15953 {
15954 static const UINT messages[] =
15955 {
15956 WM_USER-1,
15957 WM_USER,
15958 WM_USER+1,
15959 0xc000-1,
15960 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
15961 0xffff,
15962 };
15963 WNDPROC oldproc;
15964 unsigned int i;
15965 HWND hwnd;
15966
15967 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
15968 ok(hwnd != NULL, "got %p\n", hwnd);
15969
15970 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
15971 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
15972
15973 for (i = 0; i < ARRAY_SIZE(messages); i++)
15974 {
15975 BOOL ret;
15976 MSG msg;
15977
15978 flush_events();
15979 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15980 ;
15981
15982 /* post, broadcast */
15983 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
15984 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15985
15986 memset(&msg, 0xab, sizeof(msg));
15987 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15988 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15989 {
15990 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15991 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15992 }
15993 else
15994 {
15995 ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15996 }
15997
15998 /* post, topmost */
15999 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
16000 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
16001
16002 memset(&msg, 0xab, sizeof(msg));
16003 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
16004 if (messages[i] < WM_USER || messages[i] >= 0xc000)
16005 {
16006 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
16007 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
16008 }
16009 else
16010 {
16011 ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
16012 }
16013
16014 /* send, broadcast */
16015 g_broadcast_lparam = 0xdead;
16016 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16017 if (!ret && GetLastError() == ERROR_TIMEOUT)
16018 win_skip("broadcasting test %d, timeout\n", i);
16019 else
16020 {
16021 if (messages[i] < WM_USER || messages[i] >= 0xc000)
16022 {
16023 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16024 g_broadcast_lparam, GetLastError());
16025 }
16026 else
16027 {
16028 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16029 g_broadcast_lparam, GetLastError());
16030 }
16031 }
16032
16033 /* send, topmost */
16034 g_broadcast_lparam = 0xdead;
16035 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16036 if (!ret && GetLastError() == ERROR_TIMEOUT)
16037 win_skip("broadcasting test %d, timeout\n", i);
16038 else
16039 {
16040 if (messages[i] < WM_USER || messages[i] >= 0xc000)
16041 {
16042 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16043 g_broadcast_lparam, GetLastError());
16044 }
16045 else
16046 {
16047 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
16048 g_broadcast_lparam, GetLastError());
16049 }
16050 }
16051 }
16052
16053 DestroyWindow(hwnd);
16054 }
16055
16056 static const struct
16057 {
16058 DWORD exp, broken;
16059 BOOL todo;
16060 } wait_idle_expect[] =
16061 {
16062 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16063 { WAIT_TIMEOUT, 0, FALSE },
16064 { WAIT_TIMEOUT, 0, FALSE },
16065 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16066 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16067 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
16068 { WAIT_TIMEOUT, 0, FALSE },
16069 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16070 { 0, 0, FALSE },
16071 { 0, 0, FALSE },
16072 /* 10 */ { 0, 0, FALSE },
16073 { 0, 0, FALSE },
16074 { 0, WAIT_TIMEOUT, FALSE },
16075 { 0, 0, FALSE },
16076 { 0, 0, FALSE },
16077 /* 15 */ { 0, 0, FALSE },
16078 { WAIT_TIMEOUT, 0, FALSE },
16079 { WAIT_TIMEOUT, 0, FALSE },
16080 { WAIT_TIMEOUT, 0, FALSE },
16081 { WAIT_TIMEOUT, 0, FALSE },
16082 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
16083 };
16084
16085 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
16086 {
16087 MSG msg;
16088
16089 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16090 Sleep( 200 );
16091 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16092 return 0;
16093 }
16094
16095 static void do_wait_idle_child( int arg )
16096 {
16097 WNDCLASSA cls;
16098 MSG msg;
16099 HWND hwnd = 0;
16100 HANDLE thread;
16101 DWORD id;
16102 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
16103 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
16104
16105 memset( &cls, 0, sizeof(cls) );
16106 cls.lpfnWndProc = DefWindowProcA;
16107 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16108 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16109 cls.lpszClassName = "TestClass";
16110 RegisterClassA( &cls );
16111
16112 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
16113
16114 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
16115 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
16116
16117 switch (arg)
16118 {
16119 case 0:
16120 SetEvent( start_event );
16121 break;
16122 case 1:
16123 SetEvent( start_event );
16124 Sleep( 200 );
16125 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16126 break;
16127 case 2:
16128 SetEvent( start_event );
16129 Sleep( 200 );
16130 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16131 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
16132 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16133 break;
16134 case 3:
16135 SetEvent( start_event );
16136 Sleep( 200 );
16137 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
16138 break;
16139 case 4:
16140 SetEvent( start_event );
16141 Sleep( 200 );
16142 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16143 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16144 break;
16145 case 5:
16146 SetEvent( start_event );
16147 Sleep( 200 );
16148 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16149 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16150 break;
16151 case 6:
16152 SetEvent( start_event );
16153 Sleep( 200 );
16154 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16155 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
16156 {
16157 GetMessageA( &msg, 0, 0, 0 );
16158 DispatchMessageA( &msg );
16159 }
16160 break;
16161 case 7:
16162 SetEvent( start_event );
16163 Sleep( 200 );
16164 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16165 SetTimer( hwnd, 3, 1, NULL );
16166 Sleep( 200 );
16167 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16168 break;
16169 case 8:
16170 SetEvent( start_event );
16171 Sleep( 200 );
16172 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16173 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16174 break;
16175 case 9:
16176 SetEvent( start_event );
16177 Sleep( 200 );
16178 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16179 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16180 for (;;) GetMessageA( &msg, 0, 0, 0 );
16181 break;
16182 case 10:
16183 SetEvent( start_event );
16184 Sleep( 200 );
16185 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16186 SetTimer( hwnd, 3, 1, NULL );
16187 Sleep( 200 );
16188 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16189 break;
16190 case 11:
16191 SetEvent( start_event );
16192 Sleep( 200 );
16193 return; /* exiting the process makes WaitForInputIdle return success too */
16194 case 12:
16195 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16196 Sleep( 200 );
16197 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16198 SetEvent( start_event );
16199 break;
16200 case 13:
16201 SetEvent( start_event );
16202 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16203 Sleep( 200 );
16204 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
16205 WaitForSingleObject( thread, 10000 );
16206 CloseHandle( thread );
16207 break;
16208 case 14:
16209 SetEvent( start_event );
16210 Sleep( 200 );
16211 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
16212 break;
16213 case 15:
16214 SetEvent( start_event );
16215 Sleep( 200 );
16216 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
16217 break;
16218 case 16:
16219 SetEvent( start_event );
16220 Sleep( 200 );
16221 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
16222 break;
16223 case 17:
16224 SetEvent( start_event );
16225 Sleep( 200 );
16226 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
16227 break;
16228 case 18:
16229 SetEvent( start_event );
16230 Sleep( 200 );
16231 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
16232 break;
16233 case 19:
16234 SetEvent( start_event );
16235 Sleep( 200 );
16236 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
16237 break;
16238 case 20:
16239 SetEvent( start_event );
16240 Sleep( 200 );
16241 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
16242 break;
16243 }
16244 WaitForSingleObject( end_event, 2000 );
16245 CloseHandle( start_event );
16246 CloseHandle( end_event );
16247 if (hwnd) DestroyWindow( hwnd );
16248 }
16249
16250 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
16251 {
16252 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
16253 return DefWindowProcA( hwnd, msg, wp, lp );
16254 }
16255
16256 static DWORD CALLBACK wait_idle_thread( void *arg )
16257 {
16258 WNDCLASSA cls;
16259 MSG msg;
16260 HWND hwnd;
16261
16262 memset( &cls, 0, sizeof(cls) );
16263 cls.lpfnWndProc = wait_idle_proc;
16264 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16265 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16266 cls.lpszClassName = "TestClass";
16267 RegisterClassA( &cls );
16268
16269 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
16270 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
16271 DestroyWindow(hwnd);
16272 return 0;
16273 }
16274
16275 static void test_WaitForInputIdle( char *argv0 )
16276 {
16277 char path[MAX_PATH];
16278 PROCESS_INFORMATION pi;
16279 STARTUPINFOA startup;
16280 BOOL ret;
16281 HANDLE start_event, end_event, thread;
16282 unsigned int i;
16283 DWORD id;
16284 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
16285 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
16286 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
16287
16288 if (console_app) /* build the test with -mwindows for better coverage */
16289 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
16290
16291 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
16292 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
16293 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
16294 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
16295
16296 memset( &startup, 0, sizeof(startup) );
16297 startup.cb = sizeof(startup);
16298 startup.dwFlags = STARTF_USESHOWWINDOW;
16299 startup.wShowWindow = SW_SHOWNORMAL;
16300
16301 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
16302
16303 for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++)
16304 {
16305 ResetEvent( start_event );
16306 ResetEvent( end_event );
16307 #ifdef __REACTOS__
16308 sprintf( path, "%s msg_queue %u", argv0, i );
16309 #else
16310 sprintf( path, "%s msg %u", argv0, i );
16311 #endif
16312 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
16313 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
16314 if (ret)
16315 {
16316 ret = WaitForSingleObject( start_event, 5000 );
16317 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
16318 if (ret == WAIT_OBJECT_0)
16319 {
16320 ret = WaitForInputIdle( pi.hProcess, 1000 );
16321 if (ret == WAIT_FAILED)
16322 ok( console_app ||
16323 ret == wait_idle_expect[i].exp ||
16324 broken(ret == wait_idle_expect[i].broken),
16325 "%u: WaitForInputIdle error %08x expected %08x\n",
16326 i, ret, wait_idle_expect[i].exp );
16327 else todo_wine_if (wait_idle_expect[i].todo)
16328 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
16329 "%u: WaitForInputIdle error %08x expected %08x\n",
16330 i, ret, wait_idle_expect[i].exp );
16331 SetEvent( end_event );
16332 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
16333 }
16334 TerminateProcess( pi.hProcess, 0 ); /* just in case */
16335 winetest_wait_child_process( pi.hProcess );
16336 ret = WaitForInputIdle( pi.hProcess, 100 );
16337 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
16338 CloseHandle( pi.hProcess );
16339 CloseHandle( pi.hThread );
16340 }
16341 }
16342 CloseHandle( start_event );
16343 PostThreadMessageA( id, WM_QUIT, 0, 0 );
16344 WaitForSingleObject( thread, 10000 );
16345 CloseHandle( thread );
16346 }
16347
16348 static const struct message WmSetParentSeq_1[] = {
16349 { WM_SHOWWINDOW, sent|wparam, 0 },
16350 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16351 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16352 { WM_CHILDACTIVATE, sent },
16353 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
16354 { WM_MOVE, sent|defwinproc|wparam, 0 },
16355 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16356 { WM_SHOWWINDOW, sent|wparam, 1 },
16357 { 0 }
16358 };
16359
16360 static const struct message WmSetParentSeq_2[] = {
16361 { WM_SHOWWINDOW, sent|wparam, 0 },
16362 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16363 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
16364 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16365 { HCBT_SETFOCUS, hook|optional },
16366 { WM_NCACTIVATE, sent|wparam|optional, 0 },
16367 { WM_ACTIVATE, sent|wparam|optional, 0 },
16368 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
16369 { WM_KILLFOCUS, sent|wparam, 0 },
16370 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16371 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16372 { HCBT_ACTIVATE, hook|optional },
16373 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
16374 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
16375 { WM_NCACTIVATE, sent|wparam|optional, 1 },
16376 { WM_ACTIVATE, sent|wparam|optional, 1 },
16377 { HCBT_SETFOCUS, hook|optional },
16378 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16379 { WM_SETFOCUS, sent|optional|defwinproc },
16380 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
16381 { WM_MOVE, sent|defwinproc|wparam, 0 },
16382 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16383 { WM_SHOWWINDOW, sent|wparam, 1 },
16384 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16385 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
16386 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16387 { 0 }
16388 };
16389
16390
16391 static void test_SetParent(void)
16392 {
16393 HWND parent1, parent2, child, popup;
16394 RECT rc, rc_old;
16395
16396 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16397 100, 100, 200, 200, 0, 0, 0, NULL);
16398 ok(parent1 != 0, "Failed to create parent1 window\n");
16399
16400 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16401 400, 100, 200, 200, 0, 0, 0, NULL);
16402 ok(parent2 != 0, "Failed to create parent2 window\n");
16403
16404 /* WS_CHILD window */
16405 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
16406 10, 10, 150, 150, parent1, 0, 0, NULL);
16407 ok(child != 0, "Failed to create child window\n");
16408
16409 GetWindowRect(parent1, &rc);
16410 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
16411 GetWindowRect(child, &rc_old);
16412 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
16413 trace("child %s\n", wine_dbgstr_rect(&rc_old));
16414
16415 flush_sequence();
16416
16417 SetParent(child, parent2);
16418 flush_events();
16419 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE);
16420
16421 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16422 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
16423
16424 GetWindowRect(parent2, &rc);
16425 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16426 GetWindowRect(child, &rc);
16427 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
16428 trace("child %s\n", wine_dbgstr_rect(&rc));
16429
16430 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16431 wine_dbgstr_rect(&rc));
16432
16433 /* WS_POPUP window */
16434 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
16435 20, 20, 100, 100, 0, 0, 0, NULL);
16436 ok(popup != 0, "Failed to create popup window\n");
16437
16438 GetWindowRect(popup, &rc_old);
16439 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
16440
16441 flush_sequence();
16442
16443 SetParent(popup, child);
16444 flush_events();
16445 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
16446
16447 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16448 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
16449
16450 GetWindowRect(child, &rc);
16451 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16452 GetWindowRect(popup, &rc);
16453 MapWindowPoints(0, child, (POINT *)&rc, 2);
16454 trace("popup %s\n", wine_dbgstr_rect(&rc));
16455
16456 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16457 wine_dbgstr_rect(&rc));
16458
16459 DestroyWindow(popup);
16460 DestroyWindow(child);
16461 DestroyWindow(parent1);
16462 DestroyWindow(parent2);
16463
16464 flush_sequence();
16465 }
16466
16467 static const struct message WmKeyReleaseOnly[] = {
16468 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
16469 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
16470 { 0 }
16471 };
16472 static const struct message WmKeyPressNormal[] = {
16473 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
16474 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
16475 { 0 }
16476 };
16477 static const struct message WmKeyPressRepeat[] = {
16478 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
16479 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
16480 { 0 }
16481 };
16482 static const struct message WmKeyReleaseNormal[] = {
16483 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
16484 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
16485 { 0 }
16486 };
16487
16488 static void test_keyflags(void)
16489 {
16490 HWND test_window;
16491 SHORT key_state;
16492 BYTE keyboard_state[256];
16493 MSG msg;
16494
16495 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16496 100, 100, 200, 200, 0, 0, 0, NULL);
16497
16498 flush_events();
16499 flush_sequence();
16500
16501 /* keyup without a keydown */
16502 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16503 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16504 DispatchMessageA(&msg);
16505 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
16506
16507 key_state = GetAsyncKeyState(0x41);
16508 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16509
16510 key_state = GetKeyState(0x41);
16511 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16512
16513 /* keydown */
16514 keybd_event(0x41, 0, 0, 0);
16515 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16516 DispatchMessageA(&msg);
16517 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
16518
16519 key_state = GetAsyncKeyState(0x41);
16520 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16521
16522 key_state = GetKeyState(0x41);
16523 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16524
16525 /* keydown repeat */
16526 keybd_event(0x41, 0, 0, 0);
16527 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16528 DispatchMessageA(&msg);
16529 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
16530
16531 key_state = GetAsyncKeyState(0x41);
16532 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16533
16534 key_state = GetKeyState(0x41);
16535 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16536
16537 /* keyup */
16538 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16539 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16540 DispatchMessageA(&msg);
16541 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
16542
16543 key_state = GetAsyncKeyState(0x41);
16544 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16545
16546 key_state = GetKeyState(0x41);
16547 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16548
16549 /* set the key state in this thread */
16550 GetKeyboardState(keyboard_state);
16551 keyboard_state[0x41] = 0x80;
16552 SetKeyboardState(keyboard_state);
16553
16554 key_state = GetAsyncKeyState(0x41);
16555 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16556
16557 /* keydown */
16558 keybd_event(0x41, 0, 0, 0);
16559 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16560 DispatchMessageA(&msg);
16561 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16562
16563 key_state = GetAsyncKeyState(0x41);
16564 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16565
16566 key_state = GetKeyState(0x41);
16567 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16568
16569 /* clear the key state in this thread */
16570 GetKeyboardState(keyboard_state);
16571 keyboard_state[0x41] = 0;
16572 SetKeyboardState(keyboard_state);
16573
16574 key_state = GetAsyncKeyState(0x41);
16575 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16576
16577 /* keyup */
16578 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16579 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16580 DispatchMessageA(&msg);
16581 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16582
16583 key_state = GetAsyncKeyState(0x41);
16584 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16585
16586 key_state = GetKeyState(0x41);
16587 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16588
16589 DestroyWindow(test_window);
16590 flush_sequence();
16591 }
16592
16593 static const struct message WmHotkeyPressLWIN[] = {
16594 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16595 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16596 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16597 { 0 }
16598 };
16599 static const struct message WmHotkeyPress[] = {
16600 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16601 { WM_HOTKEY, sent|wparam, 5 },
16602 { 0 }
16603 };
16604 static const struct message WmHotkeyRelease[] = {
16605 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16606 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16607 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16608 { 0 }
16609 };
16610 static const struct message WmHotkeyReleaseLWIN[] = {
16611 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16612 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16613 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16614 { 0 }
16615 };
16616 static const struct message WmHotkeyCombined[] = {
16617 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16618 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16619 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16620 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16621 { WM_APP, sent, 0, 0 },
16622 { WM_HOTKEY, sent|wparam, 5 },
16623 { WM_APP+1, sent, 0, 0 },
16624 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16625 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16626 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16627 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16628 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16629 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16630 { 0 }
16631 };
16632 static const struct message WmHotkeyPrevious[] = {
16633 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16634 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16635 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16636 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16637 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16638 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16639 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16640 { WM_KEYDOWN, sent|lparam, 0, 1 },
16641 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16642 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16643 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16644 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16645 { 0 }
16646 };
16647 static const struct message WmHotkeyNew[] = {
16648 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16649 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16650 { WM_HOTKEY, sent|wparam, 5 },
16651 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16652 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16653 { 0 }
16654 };
16655
16656 static int hotkey_letter;
16657
16658 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16659 {
16660 struct recvd_message msg;
16661
16662 if (nCode == HC_ACTION)
16663 {
16664 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16665
16666 msg.hwnd = 0;
16667 msg.message = wParam;
16668 msg.flags = kbd_hook|wparam|lparam;
16669 msg.wParam = kdbhookstruct->vkCode;
16670 msg.lParam = kdbhookstruct->flags;
16671 msg.descr = "KeyboardHookProc";
16672 add_message(&msg);
16673
16674 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16675 {
16676 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
16677 "unexpected keycode %x\n", kdbhookstruct->vkCode);
16678 }
16679 }
16680
16681 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
16682 }
16683
16684 static void test_hotkey(void)
16685 {
16686 HWND test_window, taskbar_window;
16687 BOOL ret;
16688 MSG msg;
16689 DWORD queue_status;
16690 SHORT key_state;
16691
16692 SetLastError(0xdeadbeef);
16693 ret = UnregisterHotKey(NULL, 0);
16694 if (ret == TRUE)
16695 {
16696 skip("hotkeys not supported\n");
16697 return;
16698 }
16699
16700 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16701 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16702 "unexpected error %d\n", GetLastError());
16703
16704 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16705 100, 100, 200, 200, 0, 0, 0, NULL);
16706
16707 flush_sequence();
16708
16709 SetLastError(0xdeadbeef);
16710 ret = UnregisterHotKey(test_window, 0);
16711 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16712 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16713 "unexpected error %d\n", GetLastError());
16714
16715 /* Search for a Windows Key + letter combination that hasn't been registered */
16716 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
16717 {
16718 SetLastError(0xdeadbeef);
16719 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16720
16721 if (ret == TRUE)
16722 {
16723 break;
16724 }
16725 else
16726 {
16727 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16728 "unexpected error %d\n", GetLastError());
16729 }
16730 }
16731
16732 if (hotkey_letter == 0x52)
16733 {
16734 ok(0, "Couldn't find any free Windows Key + letter combination\n");
16735 goto end;
16736 }
16737
16738 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
16739 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
16740
16741 /* Same key combination, different id */
16742 SetLastError(0xdeadbeef);
16743 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
16744 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16745 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16746 "unexpected error %d\n", GetLastError());
16747
16748 /* Same key combination, different window */
16749 SetLastError(0xdeadbeef);
16750 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16751 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16752 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16753 "unexpected error %d\n", GetLastError());
16754
16755 /* Register the same hotkey twice */
16756 SetLastError(0xdeadbeef);
16757 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16758 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16759 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16760 "unexpected error %d\n", GetLastError());
16761
16762 /* Window on another thread */
16763 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
16764 if (!taskbar_window)
16765 {
16766 skip("no taskbar?\n");
16767 }
16768 else
16769 {
16770 SetLastError(0xdeadbeef);
16771 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
16772 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16773 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
16774 "unexpected error %d\n", GetLastError());
16775 }
16776
16777 /* Inject the appropriate key sequence */
16778 keybd_event(VK_LWIN, 0, 0, 0);
16779 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16780 DispatchMessageA(&msg);
16781 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
16782
16783 keybd_event(hotkey_letter, 0, 0, 0);
16784 queue_status = GetQueueStatus(QS_HOTKEY);
16785 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16786 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16787 {
16788 if (msg.message == WM_HOTKEY)
16789 {
16790 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16791 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16792 }
16793 DispatchMessageA(&msg);
16794 }
16795 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
16796
16797 queue_status = GetQueueStatus(QS_HOTKEY);
16798 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
16799
16800 key_state = GetAsyncKeyState(hotkey_letter);
16801 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16802
16803 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16804 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16805 DispatchMessageA(&msg);
16806 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
16807
16808 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16809 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16810 DispatchMessageA(&msg);
16811 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
16812
16813 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
16814 PostMessageA(test_window, WM_HOTKEY, 0, 0);
16815 queue_status = GetQueueStatus(QS_HOTKEY);
16816 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16817 queue_status = GetQueueStatus(QS_POSTMESSAGE);
16818 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
16819 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16820 DispatchMessageA(&msg);
16821 flush_sequence();
16822
16823 /* Send and process all messages at once */
16824 PostMessageA(test_window, WM_APP, 0, 0);
16825 keybd_event(VK_LWIN, 0, 0, 0);
16826 keybd_event(hotkey_letter, 0, 0, 0);
16827 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16828 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16829
16830 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16831 {
16832 if (msg.message == WM_HOTKEY)
16833 {
16834 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16835 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16836 }
16837 DispatchMessageA(&msg);
16838 }
16839 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
16840
16841 /* Register same hwnd/id with different key combination */
16842 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
16843 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16844
16845 /* Previous key combination does not work */
16846 keybd_event(VK_LWIN, 0, 0, 0);
16847 keybd_event(hotkey_letter, 0, 0, 0);
16848 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16849 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16850
16851 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16852 DispatchMessageA(&msg);
16853 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
16854
16855 /* New key combination works */
16856 keybd_event(hotkey_letter, 0, 0, 0);
16857 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16858
16859 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16860 {
16861 if (msg.message == WM_HOTKEY)
16862 {
16863 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16864 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16865 }
16866 DispatchMessageA(&msg);
16867 }
16868 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
16869
16870 /* Unregister hotkey properly */
16871 ret = UnregisterHotKey(test_window, 5);
16872 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16873
16874 /* Unregister hotkey again */
16875 SetLastError(0xdeadbeef);
16876 ret = UnregisterHotKey(test_window, 5);
16877 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16878 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16879 "unexpected error %d\n", GetLastError());
16880
16881 /* Register thread hotkey */
16882 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16883 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16884
16885 /* Inject the appropriate key sequence */
16886 keybd_event(VK_LWIN, 0, 0, 0);
16887 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16888 {
16889 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16890 DispatchMessageA(&msg);
16891 }
16892 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
16893
16894 keybd_event(hotkey_letter, 0, 0, 0);
16895 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16896 {
16897 if (msg.message == WM_HOTKEY)
16898 {
16899 struct recvd_message message;
16900 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
16901 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16902 message.message = msg.message;
16903 message.flags = sent|wparam|lparam;
16904 message.wParam = msg.wParam;
16905 message.lParam = msg.lParam;
16906 message.descr = "test_hotkey thread message";
16907 add_message(&message);
16908 }
16909 else
16910 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16911 DispatchMessageA(&msg);
16912 }
16913 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
16914
16915 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16916 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16917 {
16918 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16919 DispatchMessageA(&msg);
16920 }
16921 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
16922
16923 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16924 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16925 {
16926 ros_skip_flaky
16927 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16928 DispatchMessageA(&msg);
16929 }
16930 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
16931
16932 /* Unregister thread hotkey */
16933 ret = UnregisterHotKey(NULL, 5);
16934 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16935
16936 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
16937 hKBD_hook = NULL;
16938
16939 end:
16940 UnregisterHotKey(NULL, 5);
16941 UnregisterHotKey(test_window, 5);
16942 DestroyWindow(test_window);
16943 flush_sequence();
16944 }
16945
16946
16947 static const struct message WmSetFocus_1[] = {
16948 { HCBT_SETFOCUS, hook }, /* child */
16949 { HCBT_ACTIVATE, hook }, /* parent */
16950 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
16951 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
16952 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
16953 { WM_NCACTIVATE, sent|parent },
16954 { WM_GETTEXT, sent|defwinproc|parent|optional },
16955 { WM_GETTEXT, sent|defwinproc|parent|optional },
16956 { WM_ACTIVATE, sent|wparam|parent, 1 },
16957 { HCBT_SETFOCUS, hook }, /* parent */
16958 { WM_SETFOCUS, sent|defwinproc|parent },
16959 { WM_KILLFOCUS, sent|parent },
16960 { WM_SETFOCUS, sent },
16961 { 0 }
16962 };
16963 static const struct message WmSetFocus_2[] = {
16964 { HCBT_SETFOCUS, hook }, /* parent */
16965 { WM_KILLFOCUS, sent },
16966 { WM_SETFOCUS, sent|parent },
16967 { 0 }
16968 };
16969 static const struct message WmSetFocus_3[] = {
16970 { HCBT_SETFOCUS, hook }, /* child */
16971 { 0 }
16972 };
16973
16974 static void test_SetFocus(void)
16975 {
16976 HWND parent, old_parent, child, old_focus, old_active;
16977 MSG msg;
16978 struct wnd_event wnd_event;
16979 HANDLE hthread;
16980 DWORD ret, tid;
16981
16982 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
16983 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
16984 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
16985 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
16986 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
16987 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16988 CloseHandle(wnd_event.start_event);
16989
16990 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16991 0, 0, 0, 0, 0, 0, 0, NULL);
16992 ok(parent != 0, "failed to create parent window\n");
16993 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
16994 0, 0, 0, 0, parent, 0, 0, NULL);
16995 ok(child != 0, "failed to create child window\n");
16996
16997 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
16998
16999 SetFocus(0);
17000 SetActiveWindow(0);
17001
17002 flush_events();
17003 flush_sequence();
17004
17005 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17006 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17007
17008 log_all_parent_messages++;
17009
17010 old_focus = SetFocus(child);
17011 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17012 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
17013 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17014 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17015 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
17016
17017 old_focus = SetFocus(parent);
17018 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17019 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
17020 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
17021 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17022 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17023
17024 SetLastError(0xdeadbeef);
17025 old_focus = SetFocus((HWND)0xdeadbeef);
17026 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17027 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17028 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17029 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
17030 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17031 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17032 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17033
17034 SetLastError(0xdeadbeef);
17035 old_focus = SetFocus(GetDesktopWindow());
17036 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17037 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17038 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17039 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
17040 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17041 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17042 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17043
17044 SetLastError(0xdeadbeef);
17045 old_focus = SetFocus(wnd_event.hwnd);
17046 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17047 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17048 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17049 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
17050 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17051 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17052 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17053
17054 SetLastError(0xdeadbeef);
17055 old_active = SetActiveWindow((HWND)0xdeadbeef);
17056 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17057 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17058 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17059 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
17060 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17061 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17062 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17063
17064 SetLastError(0xdeadbeef);
17065 old_active = SetActiveWindow(GetDesktopWindow());
17066 todo_wine
17067 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17068 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17069 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
17070 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
17071 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17072 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17073
17074 SetLastError(0xdeadbeef);
17075 old_active = SetActiveWindow(wnd_event.hwnd);
17076 todo_wine
17077 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17078 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17079 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
17080 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17081 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17082 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17083
17084 SetLastError(0xdeadbeef);
17085 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
17086 ok(ret, "AttachThreadInput error %d\n", GetLastError());
17087
17088 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17089 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17090
17091 flush_events();
17092 flush_sequence();
17093
17094 old_focus = SetFocus(wnd_event.hwnd);
17095 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17096 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
17097 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17098 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17099
17100 old_focus = SetFocus(parent);
17101 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17102 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17103 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17104 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17105
17106 flush_events();
17107 flush_sequence();
17108
17109 old_active = SetActiveWindow(wnd_event.hwnd);
17110 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17111 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
17112 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17113 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17114
17115 SetLastError(0xdeadbeef);
17116 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
17117 ok(ret, "AttachThreadInput error %d\n", GetLastError());
17118
17119 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17120 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17121
17122 old_parent = SetParent(child, GetDesktopWindow());
17123 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
17124
17125 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17126 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17127
17128 old_focus = SetFocus(parent);
17129 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17130 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17131 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17132 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17133
17134 flush_events();
17135 flush_sequence();
17136
17137 SetLastError(0xdeadbeef);
17138 old_focus = SetFocus(child);
17139 todo_wine
17140 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
17141 broken(GetLastError() == 0) /* XP */ ||
17142 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
17143 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17144 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
17145 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17146 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17147 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17148
17149 SetLastError(0xdeadbeef);
17150 old_active = SetActiveWindow(child);
17151 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17152 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17153 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
17154 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
17155 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17156 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17157
17158 log_all_parent_messages--;
17159
17160 DestroyWindow(child);
17161 DestroyWindow(parent);
17162
17163 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
17164 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
17165 ret = WaitForSingleObject(hthread, INFINITE);
17166 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
17167 CloseHandle(hthread);
17168 }
17169
17170 static const struct message WmSetLayeredStyle[] = {
17171 { WM_STYLECHANGING, sent },
17172 { WM_STYLECHANGED, sent },
17173 { WM_GETTEXT, sent|defwinproc|optional },
17174 { 0 }
17175 };
17176
17177 static const struct message WmSetLayeredStyle2[] = {
17178 { WM_STYLECHANGING, sent },
17179 { WM_STYLECHANGED, sent },
17180 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17181 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
17182 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
17183 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
17184 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
17185 { 0 }
17186 };
17187
17188 struct layered_window_info
17189 {
17190 HWND hwnd;
17191 HDC hdc;
17192 SIZE size;
17193 HANDLE event;
17194 BOOL ret;
17195 };
17196
17197 static DWORD CALLBACK update_layered_proc( void *param )
17198 {
17199 struct layered_window_info *info = param;
17200 POINT src = { 0, 0 };
17201
17202 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
17203 info->hdc, &src, 0, NULL, ULW_OPAQUE );
17204 ok( info->ret, "failed\n");
17205 SetEvent( info->event );
17206 return 0;
17207 }
17208
17209 static void test_layered_window(void)
17210 {
17211 HWND hwnd;
17212 HDC hdc;
17213 HBITMAP bmp;
17214 BOOL ret;
17215 SIZE size;
17216 POINT pos, src;
17217 RECT rect, client;
17218 HANDLE thread;
17219 DWORD tid;
17220 struct layered_window_info info;
17221
17222 if (!pUpdateLayeredWindow)
17223 {
17224 win_skip( "UpdateLayeredWindow not supported\n" );
17225 return;
17226 }
17227
17228 hdc = CreateCompatibleDC( 0 );
17229 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
17230 SelectObject( hdc, bmp );
17231
17232 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
17233 100, 100, 300, 300, 0, 0, 0, NULL);
17234 ok( hwnd != 0, "failed to create window\n" );
17235 ShowWindow( hwnd, SW_SHOWNORMAL );
17236 UpdateWindow( hwnd );
17237 flush_events();
17238 flush_sequence();
17239
17240 GetWindowRect( hwnd, &rect );
17241 GetClientRect( hwnd, &client );
17242 ok( client.right < rect.right - rect.left, "wrong client area\n" );
17243 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
17244
17245 src.x = src.y = 0;
17246 pos.x = pos.y = 300;
17247 size.cx = size.cy = 250;
17248 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17249 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17250 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17251 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17252 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17253
17254 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17255 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17256 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17257 GetWindowRect( hwnd, &rect );
17258 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
17259 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17260 GetClientRect( hwnd, &rect );
17261 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
17262 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17263
17264 size.cx = 150;
17265 pos.y = 200;
17266 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17267 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17268 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17269 GetWindowRect( hwnd, &rect );
17270 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
17271 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17272 GetClientRect( hwnd, &rect );
17273 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
17274 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17275
17276 SetWindowLongA( hwnd, GWL_STYLE,
17277 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
17278 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
17279
17280 size.cx = 200;
17281 pos.x = 200;
17282 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17283 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17284 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17285 GetWindowRect( hwnd, &rect );
17286 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17287 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17288 GetClientRect( hwnd, &rect );
17289 ok( (rect.right == 200 && rect.bottom == 250) ||
17290 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17291 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17292
17293 size.cx = 0;
17294 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17295 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17296 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
17297 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
17298 size.cx = 1;
17299 size.cy = -1;
17300 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17301 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17302 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17303
17304 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
17305 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17306 GetWindowRect( hwnd, &rect );
17307 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17308 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17309 GetClientRect( hwnd, &rect );
17310 ok( (rect.right == 200 && rect.bottom == 250) ||
17311 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17312 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17313
17314 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17315 info.hwnd = hwnd;
17316 info.hdc = hdc;
17317 info.size.cx = 250;
17318 info.size.cy = 300;
17319 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
17320 info.ret = FALSE;
17321 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
17322 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
17323 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
17324 WaitForSingleObject( thread, 1000 );
17325 CloseHandle( thread );
17326 GetWindowRect( hwnd, &rect );
17327 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
17328 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17329 GetClientRect( hwnd, &rect );
17330 ok( (rect.right == 250 && rect.bottom == 300) ||
17331 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
17332 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17333
17334 DestroyWindow( hwnd );
17335 DeleteDC( hdc );
17336 DeleteObject( bmp );
17337 }
17338
17339 static HMENU hpopupmenu;
17340
17341 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17342 {
17343 if (ignore_message( message )) return 0;
17344
17345 switch (message) {
17346 case WM_ENTERIDLE:
17347 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
17348 EndMenu();
17349 break;
17350 case WM_INITMENU:
17351 case WM_INITMENUPOPUP:
17352 case WM_UNINITMENUPOPUP:
17353 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
17354 break;
17355 case WM_CAPTURECHANGED:
17356 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
17357 break;
17358 }
17359
17360 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17361 }
17362
17363 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17364 {
17365 if (ignore_message( message )) return 0;
17366
17367 switch (message) {
17368 case WM_ENTERMENULOOP:
17369 ok(EndMenu() == TRUE, "EndMenu() failed\n");
17370 break;
17371 }
17372
17373 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17374 }
17375
17376 static void test_TrackPopupMenu(void)
17377 {
17378 MSG msg;
17379 HWND hwnd;
17380 BOOL ret;
17381
17382 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17383 0, 0, 1, 1, 0,
17384 NULL, NULL, 0);
17385 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17386
17387 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17388
17389 hpopupmenu = CreatePopupMenu();
17390 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17391
17392 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
17393 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
17394
17395 flush_events();
17396 flush_sequence();
17397 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17398 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
17399 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17400
17401 /* Test popup closing with an ESC-press */
17402 flush_events();
17403 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
17404 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17405 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17406 PostQuitMessage(0);
17407 flush_sequence();
17408 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
17409 {
17410 TranslateMessage(&msg);
17411 DispatchMessageA(&msg);
17412 }
17413 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
17414
17415 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
17416
17417 flush_events();
17418 flush_sequence();
17419 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17420 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
17421 ok(ret == TRUE, "TrackPopupMenu failed\n");
17422
17423 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17424
17425 SetCapture(hwnd);
17426
17427 flush_events();
17428 flush_sequence();
17429 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17430 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
17431 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
17432
17433 DestroyMenu(hpopupmenu);
17434 DestroyWindow(hwnd);
17435 }
17436
17437 static void test_TrackPopupMenuEmpty(void)
17438 {
17439 HWND hwnd;
17440 BOOL ret;
17441
17442 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17443 0, 0, 1, 1, 0,
17444 NULL, NULL, 0);
17445 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17446
17447 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17448
17449 hpopupmenu = CreatePopupMenu();
17450 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17451
17452 flush_events();
17453 flush_sequence();
17454 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17455 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
17456 ok(ret == 0, "TrackPopupMenu succeeded\n");
17457
17458 DestroyMenu(hpopupmenu);
17459 DestroyWindow(hwnd);
17460 }
17461
17462 static const struct message send_message_1[] = {
17463 { WM_USER+2, sent|wparam|lparam, 0, 0 },
17464 { WM_USER, sent|wparam|lparam, 0, 0 },
17465 { 0 }
17466 };
17467 static const struct message send_message_2[] = {
17468 { WM_USER+4, sent|wparam|lparam, 0, 0 },
17469 { 0 }
17470 };
17471 static const struct message send_message_3[] = {
17472 { WM_USER+3, sent|wparam|lparam, 0, 0 },
17473 { WM_USER+1, sent|wparam|lparam, 0, 0 },
17474 { 0 }
17475 };
17476
17477 static DWORD WINAPI SendMessage_thread_1(void *param)
17478 {
17479 struct wnd_event *wnd_event = param;
17480
17481 trace("thread: starting\n");
17482 WaitForSingleObject(wnd_event->start_event, INFINITE);
17483
17484 trace("thread: call PostMessage\n");
17485 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17486
17487 trace("thread: call PostMessage\n");
17488 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17489
17490 trace("thread: call SendMessage\n");
17491 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17492
17493 trace("thread: call SendMessage\n");
17494 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17495
17496 return 0;
17497 }
17498
17499 static DWORD WINAPI SendMessage_thread_2(void *param)
17500 {
17501 struct wnd_event *wnd_event = param;
17502
17503 trace("thread: starting\n");
17504 WaitForSingleObject(wnd_event->start_event, INFINITE);
17505
17506 trace("thread: call PostMessage\n");
17507 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17508
17509 trace("thread: call PostMessage\n");
17510 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17511
17512 /* this leads to sending an internal message under Wine */
17513 trace("thread: call SetParent\n");
17514 SetParent(wnd_event->hwnd, wnd_event->hwnd);
17515
17516 trace("thread: call SendMessage\n");
17517 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17518
17519 trace("thread: call SendMessage\n");
17520 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17521
17522 return 0;
17523 }
17524
17525 static void test_SendMessage_other_thread(int thread_n)
17526 {
17527 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
17528 HANDLE hthread;
17529 struct wnd_event wnd_event;
17530 DWORD tid, ret;
17531 MSG msg;
17532
17533 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
17534
17535 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
17536 100, 100, 200, 200, 0, 0, 0, NULL);
17537 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
17538
17539 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
17540 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
17541 CloseHandle(hthread);
17542
17543 flush_events();
17544 flush_sequence();
17545
17546 ret = GetQueueStatus(QS_SENDMESSAGE);
17547 ok(ret == 0, "wrong status %08x\n", ret);
17548
17549 SetEvent(wnd_event.start_event);
17550
17551 /* wait for other thread's SendMessage */
17552 for (;;)
17553 {
17554 ret = GetQueueStatus(QS_SENDMESSAGE);
17555 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17556 Sleep(50);
17557 }
17558
17559 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17560 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17561
17562 trace("main: call GetMessage\n");
17563 GetMessageA(&msg, 0, 0, 0);
17564 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17565 DispatchMessageA(&msg);
17566 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17567
17568 /* intentionally yield */
17569 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17570
17571 trace("main: call SendMessage\n");
17572 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17573 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17574
17575 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17576 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17577
17578 trace("main: call PeekMessage\n");
17579 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17580 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17581 DispatchMessageA(&msg);
17582 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17583
17584 /* intentionally yield */
17585 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17586
17587 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17588 /* FIXME: remove once Wine is fixed */
17589 todo_wine_if (thread_n == 2)
17590 ok(ret == 0, "wrong status %08x\n", ret);
17591
17592 trace("main: call PeekMessage\n");
17593 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17594 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17595
17596 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17597 ok(ret == 0, "wrong status %08x\n", ret);
17598
17599 trace("main: call DestroyWindow\n");
17600 DestroyWindow(msg.hwnd);
17601
17602 flush_events();
17603 flush_sequence();
17604 }
17605
17606 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17607 {
17608 DWORD flags = InSendMessageEx( NULL );
17609 BOOL ret;
17610
17611 switch (msg)
17612 {
17613 case WM_USER:
17614 ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17615 ok( InSendMessage(), "InSendMessage returned false\n" );
17616 ret = ReplyMessage( msg );
17617 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17618 flags = InSendMessageEx( NULL );
17619 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17620 ok( InSendMessage(), "InSendMessage returned false\n" );
17621 break;
17622 case WM_USER + 1:
17623 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17624 ok( InSendMessage(), "InSendMessage returned false\n" );
17625 ret = ReplyMessage( msg );
17626 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17627 flags = InSendMessageEx( NULL );
17628 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17629 ok( InSendMessage(), "InSendMessage returned false\n" );
17630 break;
17631 case WM_USER + 2:
17632 ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17633 ok( InSendMessage(), "InSendMessage returned false\n" );
17634 ret = ReplyMessage( msg );
17635 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17636 flags = InSendMessageEx( NULL );
17637 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
17638 ok( InSendMessage(), "InSendMessage returned false\n" );
17639 break;
17640 case WM_USER + 3:
17641 ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
17642 ok( !InSendMessage(), "InSendMessage returned true\n" );
17643 ret = ReplyMessage( msg );
17644 ok( !ret, "ReplyMessage succeeded\n" );
17645 break;
17646 }
17647
17648 return DefWindowProcA( hwnd, msg, wp, lp );
17649 }
17650
17651 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
17652 {
17653 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
17654 ok( result == WM_USER + 2, "wrong result %lx\n", result );
17655 }
17656
17657 static DWORD WINAPI send_message_thread( void *arg )
17658 {
17659 HWND win = arg;
17660
17661 SendMessageA( win, WM_USER, 0, 0 );
17662 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
17663 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
17664 PostMessageA( win, WM_USER + 3, 0, 0 );
17665 PostMessageA( win, WM_QUIT, 0, 0 );
17666 return 0;
17667 }
17668
17669 static void test_InSendMessage(void)
17670 {
17671 WNDCLASSA cls;
17672 HWND win;
17673 MSG msg;
17674 HANDLE thread;
17675 DWORD tid;
17676
17677 memset(&cls, 0, sizeof(cls));
17678 cls.lpfnWndProc = insendmessage_wnd_proc;
17679 cls.hInstance = GetModuleHandleA(NULL);
17680 cls.lpszClassName = "InSendMessage_test";
17681 RegisterClassA(&cls);
17682
17683 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
17684 ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
17685
17686 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
17687 ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
17688
17689 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
17690
17691 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
17692 CloseHandle( thread );
17693
17694 DestroyWindow( win );
17695 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
17696 }
17697
17698 static const struct message DoubleSetCaptureSeq[] =
17699 {
17700 { WM_CAPTURECHANGED, sent },
17701 { 0 }
17702 };
17703
17704 static void test_DoubleSetCapture(void)
17705 {
17706 HWND hwnd;
17707
17708 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
17709 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17710 100, 100, 200, 200, 0, 0, 0, NULL);
17711 ok (hwnd != 0, "Failed to create overlapped window\n");
17712
17713 ShowWindow( hwnd, SW_SHOW );
17714 UpdateWindow( hwnd );
17715 flush_events();
17716 flush_sequence();
17717
17718 SetCapture( hwnd );
17719 SetCapture( hwnd );
17720 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
17721
17722 DestroyWindow(hwnd);
17723 }
17724
17725 static const struct message WmRestoreMinimizedSeq[] =
17726 {
17727 { HCBT_ACTIVATE, hook },
17728 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
17729 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17730 { WM_ACTIVATEAPP, sent|wparam, 1 },
17731 { WM_NCACTIVATE, sent|wparam, 0x200001 },
17732 { WM_GETTEXT, sent|defwinproc|optional },
17733 { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */
17734 { HCBT_KEYSKIPPED, hook|optional },
17735 { WM_SYSKEYUP, sent|optional },
17736 { WM_SYSCOMMAND, sent|wparam, SC_RESTORE },
17737 { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE },
17738 { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE },
17739 { HCBT_MINMAX, hook },
17740 { HCBT_MINMAX, hook|optional },
17741 { WM_QUERYOPEN, sent|defwinproc },
17742 { WM_QUERYOPEN, sent|optional },
17743 { WM_GETTEXT, sent|defwinproc|optional },
17744 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17745 { WM_GETMINMAXINFO, sent|defwinproc },
17746 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
17747 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
17748 { WM_GETTEXT, sent|defwinproc|optional },
17749 { WM_ERASEBKGND, sent|defwinproc },
17750 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17751 { WM_MOVE, sent|defwinproc },
17752 { WM_SIZE, sent|defwinproc },
17753 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
17754 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
17755 { WM_ERASEBKGND, sent|defwinproc|optional },
17756 { HCBT_SETFOCUS, hook },
17757 { WM_SETFOCUS, sent|defwinproc },
17758 { WM_ACTIVATE, sent|wparam|defwinproc, 1 },
17759 { WM_PAINT, sent| optional },
17760 { WM_SETFOCUS, sent|defwinproc|optional },
17761 { HCBT_KEYSKIPPED, hook|optional },
17762 { WM_KEYUP, sent|optional },
17763 { HCBT_KEYSKIPPED, hook|optional },
17764 { WM_SYSKEYUP, sent|optional },
17765 { HCBT_KEYSKIPPED, hook|optional },
17766 { WM_KEYUP, sent|optional },
17767 { WM_PAINT, sent| optional },
17768 { 0 }
17769 };
17770
17771 static void test_restore_messages(void)
17772 {
17773 INPUT ip = {0};
17774 HWND hwnd;
17775 INT i;
17776
17777 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100,
17778 100, 200, 200, 0, 0, 0, NULL);
17779 ok (hwnd != 0, "Failed to create overlapped window\n");
17780 SetForegroundWindow(hwnd);
17781 ShowWindow(hwnd, SW_MINIMIZE);
17782 flush_events();
17783 flush_sequence();
17784
17785 for (i = 0; i < 5; i++)
17786 {
17787 /* Send Alt+Tab to restore test window from minimized state */
17788 ip.type = INPUT_KEYBOARD;
17789 ip.ki.wVk = VK_MENU;
17790 SendInput(1, &ip, sizeof(INPUT));
17791 ip.ki.wVk = VK_TAB;
17792 SendInput(1, &ip, sizeof(INPUT));
17793 ip.ki.wVk = VK_MENU;
17794 ip.ki.dwFlags = KEYEVENTF_KEYUP;
17795 SendInput(1, &ip, sizeof(INPUT));
17796 ip.ki.wVk = VK_TAB;
17797 ip.ki.dwFlags = KEYEVENTF_KEYUP;
17798 SendInput(1, &ip, sizeof(INPUT));
17799 flush_events();
17800 if (!IsIconic(hwnd))
17801 break;
17802 }
17803
17804 if (IsIconic(hwnd))
17805 {
17806 skip("Alt+Tab failed to bring up test window.\n");
17807 goto done;
17808 }
17809 ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE);
17810
17811 done:
17812 DestroyWindow(hwnd);
17813 }
17814
17815 static void test_invalid_window(void)
17816 {
17817 MSG msg;
17818 BOOL ret;
17819
17820 SetLastError(0xdeadbeef);
17821 ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0);
17822 ok(ret == -1, "wrong ret %d\n", ret);
17823 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
17824
17825 SetLastError(0xdeadbeef);
17826 ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE);
17827 ok(!ret, "wrong ret %d\n", ret);
17828 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
17829 }
17830
17831 static void init_funcs(void)
17832 {
17833 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
17834
17835 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
17836 X(ActivateActCtx);
17837 X(CreateActCtxW);
17838 X(DeactivateActCtx);
17839 X(GetCurrentActCtx);
17840 X(QueryActCtxW);
17841 X(ReleaseActCtx);
17842 #undef X
17843 }
17844
17845 #ifndef __REACTOS__
17846 START_TEST(msg)
17847 {
17848 char **test_argv;
17849 BOOL ret;
17850 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17851 HMODULE hModuleImm32;
17852 BOOL (WINAPI *pImmDisableIME)(DWORD);
17853 int argc;
17854
17855 init_funcs();
17856
17857 argc = winetest_get_mainargs( &test_argv );
17858 if (argc >= 3)
17859 {
17860 unsigned int arg;
17861 /* Child process. */
17862 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17863 do_wait_idle_child( arg );
17864 return;
17865 }
17866
17867 InitializeCriticalSection( &sequence_cs );
17868 init_procs();
17869
17870 hModuleImm32 = LoadLibraryA("imm32.dll");
17871 if (hModuleImm32) {
17872 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17873 if (pImmDisableIME)
17874 pImmDisableIME(0);
17875 }
17876 pImmDisableIME = NULL;
17877 FreeLibrary(hModuleImm32);
17878
17879 if (!RegisterWindowClasses()) assert(0);
17880
17881 if (pSetWinEventHook)
17882 {
17883 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17884 GetModuleHandleA(0), win_event_proc,
17885 0, GetCurrentThreadId(),
17886 WINEVENT_INCONTEXT);
17887 if (pIsWinEventHookInstalled && hEvent_hook)
17888 {
17889 UINT event;
17890 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17891 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17892 }
17893 }
17894 if (!hEvent_hook) win_skip( "no win event hook support\n" );
17895
17896 cbt_hook_thread_id = GetCurrentThreadId();
17897 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17898 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17899
17900 test_winevents();
17901
17902 /* Fix message sequences before removing 4 lines below */
17903 if (pUnhookWinEvent && hEvent_hook)
17904 {
17905 ret = pUnhookWinEvent(hEvent_hook);
17906 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17907 pUnhookWinEvent = 0;
17908 }
17909 hEvent_hook = 0;
17910
17911 test_SendMessage_other_thread(1);
17912 test_SendMessage_other_thread(2);
17913 test_InSendMessage();
17914 test_SetFocus();
17915 test_SetParent();
17916 test_PostMessage();
17917 test_broadcast();
17918 test_ShowWindow();
17919 test_PeekMessage();
17920 test_PeekMessage2();
17921 test_PeekMessage3();
17922 test_WaitForInputIdle( test_argv[0] );
17923 test_scrollwindowex();
17924 test_messages();
17925 test_setwindowpos();
17926 test_showwindow();
17927 test_recursive_activation();
17928 invisible_parent_tests();
17929 test_mdi_messages();
17930 test_button_messages();
17931 test_button_bm_get_set_image();
17932 test_autoradio_BM_CLICK();
17933 test_autoradio_kbd_move();
17934 test_static_messages();
17935 test_listbox_messages();
17936 test_combobox_messages();
17937 test_wmime_keydown_message();
17938 test_paint_messages();
17939 test_interthread_messages();
17940 test_message_conversion();
17941 test_accelerators();
17942 test_timers();
17943 test_timers_no_wnd();
17944 test_timers_exceptions();
17945 if (hCBT_hook)
17946 {
17947 test_set_hook();
17948 test_recursive_hook();
17949 }
17950 test_DestroyWindow();
17951 test_DispatchMessage();
17952 test_SendMessageTimeout();
17953 test_edit_messages();
17954 test_quit_message();
17955 test_notify_message();
17956 test_SetActiveWindow();
17957 test_restore_messages();
17958 test_invalid_window();
17959
17960 if (!pTrackMouseEvent)
17961 win_skip("TrackMouseEvent is not available\n");
17962 else
17963 test_TrackMouseEvent();
17964
17965 test_SetWindowRgn();
17966 test_sys_menu();
17967 test_dialog_messages();
17968 test_EndDialog();
17969 test_nullCallback();
17970 test_dbcs_wm_char();
17971 test_unicode_wm_char();
17972 test_menu_messages();
17973 test_paintingloop();
17974 test_defwinproc();
17975 test_desktop_winproc();
17976 test_clipboard_viewers();
17977 test_keyflags();
17978 test_hotkey();
17979 test_layered_window();
17980 test_TrackPopupMenu();
17981 test_TrackPopupMenuEmpty();
17982 test_DoubleSetCapture();
17983 /* keep it the last test, under Windows it tends to break the tests
17984 * which rely on active/foreground windows being correct.
17985 */
17986 test_SetForegroundWindow();
17987
17988 UnhookWindowsHookEx(hCBT_hook);
17989 if (pUnhookWinEvent && hEvent_hook)
17990 {
17991 ret = pUnhookWinEvent(hEvent_hook);
17992 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17993 SetLastError(0xdeadbeef);
17994 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17995 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17996 GetLastError() == 0xdeadbeef, /* Win9x */
17997 "unexpected error %d\n", GetLastError());
17998 }
17999 DeleteCriticalSection( &sequence_cs );
18000 }
18001 #endif /* __REACTOS__ */
18002
18003 static void init_tests()
18004 {
18005 HMODULE hModuleImm32;
18006 BOOL (WINAPI *pImmDisableIME)(DWORD);
18007
18008 init_funcs();
18009
18010 InitializeCriticalSection( &sequence_cs );
18011 init_procs();
18012
18013 hModuleImm32 = LoadLibraryA("imm32.dll");
18014 if (hModuleImm32) {
18015 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
18016 if (pImmDisableIME)
18017 pImmDisableIME(0);
18018 }
18019 pImmDisableIME = NULL;
18020 FreeLibrary(hModuleImm32);
18021
18022 if (!RegisterWindowClasses()) assert(0);
18023
18024 cbt_hook_thread_id = GetCurrentThreadId();
18025 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
18026 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
18027 }
18028
18029 static void cleanup_tests()
18030 {
18031 BOOL ret;
18032 UnhookWindowsHookEx(hCBT_hook);
18033 if (pUnhookWinEvent && hEvent_hook)
18034 {
18035 ret = pUnhookWinEvent(hEvent_hook);
18036 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18037 SetLastError(0xdeadbeef);
18038 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
18039 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
18040 GetLastError() == 0xdeadbeef, /* Win9x */
18041 "unexpected error %d\n", GetLastError());
18042 }
18043 DeleteCriticalSection( &sequence_cs );
18044
18045 }
18046
18047 START_TEST(msg_queue)
18048 {
18049 int argc;
18050 char **test_argv;
18051 argc = winetest_get_mainargs( &test_argv );
18052 if (argc >= 3)
18053 {
18054 unsigned int arg;
18055 /* Child process. */
18056 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
18057 do_wait_idle_child( arg );
18058 return;
18059 }
18060
18061 init_tests();
18062 test_SendMessage_other_thread(1);
18063 test_SendMessage_other_thread(2);
18064 test_InSendMessage();
18065 test_PostMessage();
18066 test_broadcast();
18067 test_PeekMessage();
18068 test_PeekMessage2();
18069 test_PeekMessage3();
18070 test_interthread_messages();
18071 test_DispatchMessage();
18072 test_SendMessageTimeout();
18073 test_quit_message();
18074 test_notify_message();
18075 test_WaitForInputIdle( test_argv[0] );
18076 test_DestroyWindow();
18077 cleanup_tests();
18078 }
18079
18080 START_TEST(msg_messages)
18081 {
18082 init_tests();
18083 test_message_conversion();
18084 test_messages();
18085 test_wmime_keydown_message();
18086 test_nullCallback();
18087 test_dbcs_wm_char();
18088 test_unicode_wm_char();
18089 test_defwinproc();
18090 test_desktop_winproc();
18091 cleanup_tests();
18092 }
18093
18094 START_TEST(msg_focus)
18095 {
18096 init_tests();
18097
18098 test_SetFocus();
18099
18100 /* HACK: For some reason the tests fail on Windows if run consecutively.
18101 * Putting these in between helps, and is essentially what happens in the
18102 * "normal" msg test. */
18103 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
18104 flush_events();
18105
18106 test_SetActiveWindow();
18107
18108 /* HACK */
18109 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
18110 flush_events();
18111
18112 test_restore_messages();
18113 test_invalid_window();
18114
18115 test_DoubleSetCapture();
18116
18117 /* keep it the last test, under Windows it tends to break the tests
18118 * which rely on active/foreground windows being correct.
18119 */
18120 test_SetForegroundWindow();
18121 cleanup_tests();
18122 }
18123
18124 START_TEST(msg_winpos)
18125 {
18126 init_tests();
18127 test_SetParent();
18128 test_ShowWindow();
18129 test_setwindowpos();
18130 test_showwindow();
18131 test_recursive_activation();
18132 test_SetWindowRgn();
18133 invisible_parent_tests();
18134 cleanup_tests();
18135 }
18136
18137 START_TEST(msg_paint)
18138 {
18139 init_tests();
18140 test_scrollwindowex();
18141 test_paint_messages();
18142 #ifdef __REACTOS__
18143 if (!winetest_interactive &&
18144 !strcmp(winetest_platform, "windows"))
18145 {
18146 skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
18147 }
18148 else
18149 #endif
18150 test_paintingloop();
18151 cleanup_tests();
18152 }
18153
18154 START_TEST(msg_input)
18155 {
18156 init_tests();
18157 test_accelerators();
18158 if (!pTrackMouseEvent)
18159 win_skip("TrackMouseEvent is not available\n");
18160 else
18161 test_TrackMouseEvent();
18162
18163 test_keyflags();
18164 test_hotkey();
18165 cleanup_tests();
18166 }
18167
18168 START_TEST(msg_timer)
18169 {
18170 init_tests();
18171 test_timers();
18172 test_timers_no_wnd();
18173 test_timers_exceptions();
18174 cleanup_tests();
18175 }
18176
18177 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
18178
18179 START_TEST(msg_hook)
18180 {
18181 // HMODULE user32 = GetModuleHandleA("user32.dll");
18182 // IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
18183 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
18184
18185 init_tests();
18186
18187 if (pSetWinEventHook)
18188 {
18189 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
18190 GetModuleHandleA(0), win_event_proc,
18191 0, GetCurrentThreadId(),
18192 WINEVENT_INCONTEXT);
18193 if (pIsWinEventHookInstalled && hEvent_hook)
18194 {
18195 UINT event;
18196 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
18197 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
18198 }
18199 }
18200 if (!hEvent_hook) win_skip( "no win event hook support\n" );
18201
18202 test_winevents();
18203
18204 /* Fix message sequences before removing 4 lines below */
18205 if (pUnhookWinEvent && hEvent_hook)
18206 {
18207 BOOL ret;
18208 ret = pUnhookWinEvent(hEvent_hook);
18209 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18210 pUnhookWinEvent = 0;
18211 }
18212 hEvent_hook = 0;
18213 if (hCBT_hook)
18214 {
18215 test_set_hook();
18216 test_recursive_hook();
18217 }
18218 cleanup_tests();
18219 }
18220
18221 START_TEST(msg_menu)
18222 {
18223 init_tests();
18224 test_sys_menu();
18225 test_menu_messages();
18226 test_TrackPopupMenu();
18227 test_TrackPopupMenuEmpty();
18228 cleanup_tests();
18229 }
18230
18231 START_TEST(msg_mdi)
18232 {
18233 init_tests();
18234 test_mdi_messages();
18235 cleanup_tests();
18236 }
18237
18238 START_TEST(msg_controls)
18239 {
18240 init_tests();
18241 test_button_messages();
18242 test_button_bm_get_set_image();
18243 test_autoradio_BM_CLICK();
18244 test_autoradio_kbd_move();
18245 test_static_messages();
18246 test_listbox_messages();
18247 test_combobox_messages();
18248 test_edit_messages();
18249 cleanup_tests();
18250 }
18251
18252 START_TEST(msg_layered_window)
18253 {
18254 init_tests();
18255 test_layered_window();
18256 cleanup_tests();
18257 }
18258
18259 START_TEST(msg_dialog)
18260 {
18261 init_tests();
18262 test_dialog_messages();
18263 test_EndDialog();
18264 cleanup_tests();
18265 }
18266
18267 START_TEST(msg_clipboard)
18268 {
18269 init_tests();
18270 test_clipboard_viewers();
18271 cleanup_tests();
18272 }