Remove unnecessary executable bits
[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 #ifndef __REACTOS__
24 #define _WIN32_WINNT 0x0600 /* For WM_CHANGEUISTATE,QS_RAWINPUT,WM_DWMxxxx */
25 #define WINVER 0x0600 /* for WM_GETTITLEBARINFOEX */
26 #endif
27
28 #include <assert.h>
29 #include <limits.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winnls.h"
38 #include "dbt.h"
39
40 #include "wine/test.h"
41
42 #define MDI_FIRST_CHILD_ID 2004
43
44 /* undocumented SWP flags - from SDK 3.1 */
45 #define SWP_NOCLIENTSIZE 0x0800
46 #define SWP_NOCLIENTMOVE 0x1000
47 #define SWP_STATECHANGED 0x8000
48
49 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
50
51 #ifndef WM_KEYF1
52 #define WM_KEYF1 0x004d
53 #endif
54
55 #ifndef WM_SYSTIMER
56 #define WM_SYSTIMER 0x0118
57 #endif
58
59 #define WND_PARENT_ID 1
60 #define WND_POPUP_ID 2
61 #define WND_CHILD_ID 3
62
63 #ifndef WM_LBTRACKPOINT
64 #define WM_LBTRACKPOINT 0x0131
65 #endif
66
67 #ifdef __i386__
68 #define ARCH "x86"
69 #elif defined __x86_64__
70 #define ARCH "amd64"
71 #elif defined __arm__
72 #define ARCH "arm"
73 #elif defined __aarch64__
74 #define ARCH "arm64"
75 #else
76 #define ARCH "none"
77 #endif
78
79 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
80 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
81 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
82 static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
83 static BOOL (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
84 static void (WINAPI *pReleaseActCtx)(HANDLE);
85
86 /* encoded DRAWITEMSTRUCT into an LPARAM */
87 typedef struct
88 {
89 union
90 {
91 struct
92 {
93 UINT type : 4; /* ODT_* flags */
94 UINT ctl_id : 4; /* Control ID */
95 UINT item_id : 4; /* Menu item ID */
96 UINT action : 4; /* ODA_* flags */
97 UINT state : 16; /* ODS_* flags */
98 } item;
99 LPARAM lp;
100 } u;
101 } DRAW_ITEM_STRUCT;
102
103 /* encoded MEASUREITEMSTRUCT into a WPARAM */
104 typedef struct
105 {
106 union
107 {
108 struct
109 {
110 UINT CtlType : 4;
111 UINT CtlID : 4;
112 UINT itemID : 4;
113 UINT wParam : 20;
114 } item;
115 WPARAM wp;
116 } u;
117 } MEASURE_ITEM_STRUCT;
118
119 static BOOL test_DestroyWindow_flag;
120 static HWINEVENTHOOK hEvent_hook;
121 static HHOOK hKBD_hook;
122 static HHOOK hCBT_hook;
123 static DWORD cbt_hook_thread_id;
124
125 static const WCHAR testWindowClassW[] =
126 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
127
128 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
129
130 /*
131 FIXME: add tests for these
132 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
133 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
134 WS_THICKFRAME: thick border
135 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
136 WS_BORDER (default for overlapped windows): single black border
137 none (default for child (and popup?) windows): no border
138 */
139
140 typedef enum {
141 sent=0x1,
142 posted=0x2,
143 parent=0x4,
144 wparam=0x8,
145 lparam=0x10,
146 defwinproc=0x20,
147 beginpaint=0x40,
148 optional=0x80,
149 hook=0x100,
150 winevent_hook=0x200,
151 kbd_hook=0x400
152 } msg_flags_t;
153
154 struct message {
155 UINT message; /* the WM_* code */
156 msg_flags_t flags; /* message props */
157 WPARAM wParam; /* expected value of wParam */
158 LPARAM lParam; /* expected value of lParam */
159 WPARAM wp_mask; /* mask for wParam checks */
160 LPARAM lp_mask; /* mask for lParam checks */
161 };
162
163 struct recvd_message {
164 UINT message; /* the WM_* code */
165 msg_flags_t flags; /* message props */
166 HWND hwnd; /* window that received the message */
167 WPARAM wParam; /* expected value of wParam */
168 LPARAM lParam; /* expected value of lParam */
169 int line; /* source line where logged */
170 const char *descr; /* description for trace output */
171 char output[512]; /* trace output */
172 };
173
174 /* Empty message sequence */
175 static const struct message WmEmptySeq[] =
176 {
177 { 0 }
178 };
179 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
180 static const struct message WmCreateOverlappedSeq[] = {
181 { HCBT_CREATEWND, hook },
182 { WM_GETMINMAXINFO, sent },
183 { WM_NCCREATE, sent },
184 { WM_NCCALCSIZE, sent|wparam, 0 },
185 { 0x0093, sent|defwinproc|optional },
186 { 0x0094, sent|defwinproc|optional },
187 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
188 { WM_CREATE, sent },
189 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
190 { 0 }
191 };
192 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
193 * for a not visible overlapped window.
194 */
195 static const struct message WmSWP_ShowOverlappedSeq[] = {
196 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
197 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
198 { WM_NCPAINT, sent|wparam|optional, 1 },
199 { WM_GETTEXT, sent|defwinproc|optional },
200 { WM_ERASEBKGND, sent|optional },
201 { HCBT_ACTIVATE, hook },
202 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
203 { WM_NOTIFYFORMAT, sent|optional },
204 { WM_QUERYUISTATE, sent|optional },
205 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
206 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
207 { WM_ACTIVATEAPP, sent|wparam, 1 },
208 { WM_NCACTIVATE, sent },
209 { WM_GETTEXT, sent|defwinproc|optional },
210 { WM_ACTIVATE, sent|wparam, 1 },
211 { HCBT_SETFOCUS, hook },
212 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
213 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
214 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
215 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
216 { WM_GETTEXT, sent|optional },
217 { WM_NCPAINT, sent|wparam|optional, 1 },
218 { WM_GETTEXT, sent|defwinproc|optional },
219 { WM_ERASEBKGND, sent|optional },
220 /* Win9x adds SWP_NOZORDER below */
221 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
222 { WM_GETTEXT, sent|optional },
223 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
224 { WM_NCPAINT, sent|wparam|optional, 1 },
225 { WM_ERASEBKGND, sent|optional },
226 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
227 { WM_SYNCPAINT, sent|optional },
228 { WM_GETTITLEBARINFOEX, sent|optional },
229 { WM_PAINT, sent|optional },
230 { WM_NCPAINT, sent|beginpaint|optional },
231 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
232 { WM_ERASEBKGND, sent|beginpaint|optional },
233 { 0 }
234 };
235 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
236 * for a visible overlapped window.
237 */
238 static const struct message WmSWP_HideOverlappedSeq[] = {
239 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
240 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
241 { HCBT_ACTIVATE, hook|optional },
242 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
243 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
244 { WM_NCACTIVATE, sent|optional },
245 { WM_ACTIVATE, sent|optional },
246 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
247 { 0 }
248 };
249
250 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
251 * for a visible overlapped window.
252 */
253 static const struct message WmSWP_ResizeSeq[] = {
254 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
255 { WM_GETMINMAXINFO, sent|defwinproc },
256 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
257 { WM_NCPAINT, sent|optional },
258 { WM_GETTEXT, sent|defwinproc|optional },
259 { WM_ERASEBKGND, sent|optional },
260 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
261 { WM_SIZE, sent|defwinproc|optional },
262 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
263 { WM_NCPAINT, sent|optional },
264 { WM_GETTEXT, sent|defwinproc|optional },
265 { WM_ERASEBKGND, sent|optional },
266 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
267 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
268 { 0 }
269 };
270
271 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
272 * for a visible popup window.
273 */
274 static const struct message WmSWP_ResizePopupSeq[] = {
275 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
276 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
277 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
278 { WM_NCPAINT, sent|optional },
279 { WM_GETTEXT, sent|defwinproc|optional },
280 { WM_ERASEBKGND, sent|optional },
281 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
282 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
283 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
284 { WM_NCPAINT, sent|optional },
285 { WM_GETTEXT, sent|defwinproc|optional },
286 { WM_ERASEBKGND, sent|optional },
287 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
288 { 0 }
289 };
290
291 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
292 * for a visible overlapped window.
293 */
294 static const struct message WmSWP_MoveSeq[] = {
295 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
296 { WM_NCPAINT, sent|optional },
297 { WM_GETTEXT, sent|defwinproc|optional },
298 { WM_ERASEBKGND, sent|optional },
299 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
300 { WM_MOVE, sent|defwinproc|wparam, 0 },
301 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
302 { 0 }
303 };
304 /* Resize with SetWindowPos(SWP_NOZORDER)
305 * for a visible overlapped window
306 * SWP_NOZORDER is stripped by the logging code
307 */
308 static const struct message WmSWP_ResizeNoZOrder[] = {
309 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
310 { WM_GETMINMAXINFO, sent|defwinproc },
311 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
312 { WM_NCPAINT, sent|optional },
313 { WM_GETTEXT, sent|defwinproc|optional },
314 { WM_ERASEBKGND, sent|optional },
315 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
316 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
317 { WM_MOVE, sent|defwinproc|optional },
318 { WM_SIZE, sent|defwinproc|optional },
319 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
320 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
321 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
322 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
323 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
324 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
325 { 0 }
326 };
327
328 /* Switch visible mdi children */
329 static const struct message WmSwitchChild[] = {
330 /* Switch MDI child */
331 { WM_MDIACTIVATE, sent },/* in the MDI client */
332 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
333 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
334 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
335 /* Deactivate 2nd MDI child */
336 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
337 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
338 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
339 /* Preparing for maximize and maximize the 1st MDI child */
340 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
341 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
342 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
343 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
344 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
345 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
346 /* Lock redraw 2nd MDI child */
347 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
348 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
349 /* Restore 2nd MDI child */
350 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
351 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
352 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
353 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
354 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
355 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
356 /* Redraw 2nd MDI child */
357 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
358 /* Redraw MDI frame */
359 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
360 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
361 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
362 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
363 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
364 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
365 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
366 { HCBT_SETFOCUS, hook },
367 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
368 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
369 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
370 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
371 { WM_SETFOCUS, sent },/* in the MDI client */
372 { HCBT_SETFOCUS, hook },
373 { WM_KILLFOCUS, sent },/* in the MDI client */
374 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
375 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
376 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
377 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
378 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
379 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
380 { 0 }
381 };
382
383 /* Switch visible not maximized mdi children */
384 static const struct message WmSwitchNotMaximizedChild[] = {
385 /* Switch not maximized MDI child */
386 { WM_MDIACTIVATE, sent },/* in the MDI client */
387 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
388 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
389 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
390 /* Deactivate 1st MDI child */
391 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
392 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
393 /* Activate 2nd MDI child */
394 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
395 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
396 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
397 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
398 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
399 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
400 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
401 { HCBT_SETFOCUS, hook },
402 { WM_KILLFOCUS, sent }, /* in the MDI client */
403 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
404 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
405 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
406 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
407 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
408 { 0 }
409 };
410
411
412 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
413 SWP_NOZORDER|SWP_FRAMECHANGED)
414 * for a visible overlapped window with WS_CLIPCHILDREN style set.
415 */
416 static const struct message WmSWP_FrameChanged_clip[] = {
417 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
418 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
419 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
420 { WM_GETTEXT, sent|parent|defwinproc|optional },
421 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
422 { WM_NCPAINT, sent }, /* wparam != 1 */
423 { WM_ERASEBKGND, sent },
424 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
425 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
426 { WM_PAINT, sent },
427 { 0 }
428 };
429 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
430 SWP_NOZORDER|SWP_FRAMECHANGED)
431 * for a visible overlapped window.
432 */
433 static const struct message WmSWP_FrameChangedDeferErase[] = {
434 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
435 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
436 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
437 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
438 { WM_PAINT, sent|parent|optional },
439 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
440 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
441 { WM_PAINT, sent },
442 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
443 { WM_ERASEBKGND, sent|beginpaint|optional },
444 { 0 }
445 };
446
447 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
448 SWP_NOZORDER|SWP_FRAMECHANGED)
449 * for a visible overlapped window without WS_CLIPCHILDREN style set.
450 */
451 static const struct message WmSWP_FrameChanged_noclip[] = {
452 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
453 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
454 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
455 { WM_GETTEXT, sent|parent|defwinproc|optional },
456 { WM_ERASEBKGND, sent|parent|optional },
457 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
458 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
459 { WM_PAINT, sent },
460 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
461 { WM_ERASEBKGND, sent|beginpaint|optional },
462 { 0 }
463 };
464
465 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
466 static const struct message WmShowOverlappedSeq[] = {
467 { WM_SHOWWINDOW, sent|wparam, 1 },
468 { WM_NCPAINT, sent|wparam|optional, 1 },
469 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
470 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
471 { WM_NCPAINT, sent|wparam|optional, 1 },
472 { WM_GETTEXT, sent|defwinproc|optional },
473 { WM_ERASEBKGND, sent|optional },
474 { HCBT_ACTIVATE, hook|optional },
475 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
476 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
477 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
478 { WM_NCPAINT, sent|wparam|optional, 1 },
479 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
480 { WM_NCACTIVATE, sent|wparam|optional, 1 },
481 { WM_GETTEXT, sent|defwinproc|optional },
482 { WM_ACTIVATE, sent|wparam|optional, 1 },
483 { HCBT_SETFOCUS, hook|optional },
484 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
485 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
486 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
487 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
488 { WM_GETTEXT, sent|optional },
489 { WM_NCPAINT, sent|wparam|optional, 1 },
490 { WM_GETTEXT, sent|defwinproc|optional },
491 { WM_ERASEBKGND, sent|optional },
492 /* Win9x adds SWP_NOZORDER below */
493 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
494 { WM_NCCALCSIZE, sent|optional },
495 { WM_GETTEXT, sent|optional },
496 { WM_NCPAINT, sent|optional },
497 { WM_ERASEBKGND, sent|optional },
498 { WM_SYNCPAINT, sent|optional },
499 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
500 * messages. Does that mean that CreateWindow doesn't set initial
501 * window dimensions for overlapped windows?
502 */
503 { WM_SIZE, sent },
504 { WM_MOVE, sent },
505 #endif
506 { WM_PAINT, sent|optional },
507 { WM_NCPAINT, sent|beginpaint|optional },
508 { 0 }
509 };
510 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
511 static const struct message WmShowMaxOverlappedSeq[] = {
512 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
513 { WM_GETMINMAXINFO, sent },
514 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
515 { WM_GETMINMAXINFO, sent|defwinproc },
516 { WM_NCCALCSIZE, sent|wparam, TRUE },
517 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
518 { HCBT_ACTIVATE, hook|optional },
519 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
520 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
521 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
522 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
523 { WM_NCACTIVATE, sent|wparam|optional, 1 },
524 { WM_GETTEXT, sent|defwinproc|optional },
525 { WM_ACTIVATE, sent|wparam|optional, 1 },
526 { HCBT_SETFOCUS, hook|optional },
527 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
528 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
529 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
530 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
531 { WM_GETTEXT, sent|optional },
532 { WM_NCPAINT, sent|wparam|optional, 1 },
533 { WM_GETTEXT, sent|defwinproc|optional },
534 { WM_ERASEBKGND, sent|optional },
535 /* Win9x adds SWP_NOZORDER below */
536 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
537 { WM_MOVE, sent|defwinproc },
538 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
539 { WM_GETTEXT, sent|optional },
540 { WM_NCCALCSIZE, sent|optional },
541 { WM_NCPAINT, sent|optional },
542 { WM_ERASEBKGND, sent|optional },
543 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
544 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
545 { WM_SYNCPAINT, sent|optional },
546 { WM_GETTITLEBARINFOEX, sent|optional },
547 { WM_PAINT, sent|optional },
548 { WM_NCPAINT, sent|beginpaint|optional },
549 { WM_ERASEBKGND, sent|beginpaint|optional },
550 { 0 }
551 };
552 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
553 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
554 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
555 { WM_GETTEXT, sent|optional },
556 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
557 { WM_GETMINMAXINFO, sent|defwinproc },
558 { WM_NCCALCSIZE, sent|wparam, TRUE },
559 { WM_NCPAINT, sent|optional },
560 { WM_GETTEXT, sent|defwinproc|optional },
561 { WM_ERASEBKGND, sent|optional },
562 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
563 { WM_MOVE, sent|defwinproc|optional },
564 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
565 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
566 { WM_NCPAINT, sent|optional },
567 { WM_ERASEBKGND, sent|optional },
568 { WM_PAINT, sent|optional },
569 { WM_GETTITLEBARINFOEX, sent|optional },
570 { WM_NCPAINT, sent|beginpaint|optional },
571 { WM_ERASEBKGND, sent|beginpaint|optional },
572 { 0 }
573 };
574 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
575 static const struct message WmShowRestoreMinOverlappedSeq[] = {
576 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
577 { WM_QUERYOPEN, sent|optional },
578 { WM_GETTEXT, sent|optional },
579 { WM_NCACTIVATE, sent|wparam|optional, 1 },
580 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
581 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
582 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
583 { WM_MOVE, sent|optional },
584 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
585 { WM_GETTEXT, sent|optional },
586 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
587 { WM_GETMINMAXINFO, sent|defwinproc|optional },
588 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
589 { HCBT_ACTIVATE, hook|optional },
590 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
591 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
592 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
593 { WM_NCACTIVATE, sent|wparam|optional, 1 },
594 { WM_GETTEXT, sent|defwinproc|optional },
595 { WM_ACTIVATE, sent|wparam|optional, 1 },
596 { HCBT_SETFOCUS, hook|optional },
597 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
598 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
599 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
600 { WM_GETTEXT, sent|optional },
601 { WM_NCPAINT, sent|wparam|optional, 1 },
602 { WM_GETTEXT, sent|defwinproc|optional },
603 { WM_ERASEBKGND, sent },
604 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
605 { WM_MOVE, sent|defwinproc },
606 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
607 { HCBT_SETFOCUS, hook|optional },
608 { WM_SETFOCUS, sent|wparam|optional, 0 },
609 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
610 { WM_NCPAINT, sent|wparam|optional, 1 },
611 { WM_ERASEBKGND, sent|optional },
612 { HCBT_SETFOCUS, hook|optional },
613 { WM_SETFOCUS, sent|wparam|optional, 0 },
614 { WM_ACTIVATE, sent|wparam, 1 },
615 { WM_GETTEXT, sent|optional },
616 { WM_PAINT, sent|optional },
617 { WM_GETTITLEBARINFOEX, sent|optional },
618 { WM_NCPAINT, sent|beginpaint|optional },
619 { WM_ERASEBKGND, sent|beginpaint|optional },
620 { 0 }
621 };
622 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
623 static const struct message WmShowMinOverlappedSeq[] = {
624 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
625 { HCBT_SETFOCUS, hook|optional },
626 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
627 { WM_KILLFOCUS, sent|optional },
628 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
629 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
630 { WM_GETTEXT, sent|optional },
631 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
632 { WM_GETMINMAXINFO, sent|defwinproc },
633 { WM_NCCALCSIZE, sent|wparam, TRUE },
634 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
635 { WM_NCPAINT, sent|optional },
636 { WM_GETTEXT, sent|defwinproc|optional },
637 { WM_WINDOWPOSCHANGED, sent },
638 { WM_MOVE, sent|defwinproc },
639 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
640 { WM_NCCALCSIZE, sent|optional },
641 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
642 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
643 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
644 { WM_NCACTIVATE, sent|wparam|optional, 0 },
645 { WM_GETTEXT, sent|defwinproc|optional },
646 { WM_ACTIVATE, sent|optional },
647 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
648
649 /* Vista sometimes restores the window right away... */
650 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
651 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
652 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
653 { WM_QUERYOPEN, sent|optional },
654 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
655 { WM_GETMINMAXINFO, sent|optional|defwinproc },
656 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
657 { HCBT_ACTIVATE, hook|optional },
658 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
659 { WM_NCACTIVATE, sent|optional },
660 { WM_GETTEXT, sent|optional },
661 { WM_ACTIVATE, sent|optional|wparam, 1 },
662 { HCBT_SETFOCUS, hook|optional },
663 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
664 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
665 { WM_SETFOCUS, sent|optional },
666 { WM_NCPAINT, sent|optional },
667 { WM_GETTEXT, sent|defwinproc|optional },
668 { WM_ERASEBKGND, sent|optional },
669 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
670 { WM_MOVE, sent|defwinproc|optional },
671 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
672 { WM_ACTIVATE, sent|optional|wparam, 1 },
673 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
674 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
675
676 { WM_PAINT, sent|optional },
677 { WM_NCPAINT, sent|beginpaint|optional },
678 { WM_ERASEBKGND, sent|beginpaint|optional },
679 { 0 }
680 };
681 /* ShowWindow(SW_HIDE) for a visible overlapped window */
682 static const struct message WmHideOverlappedSeq[] = {
683 { WM_SHOWWINDOW, sent|wparam, 0 },
684 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
685 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
686 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
687 { WM_SIZE, sent|optional }, /* XP doesn't send it */
688 { WM_MOVE, sent|optional }, /* XP doesn't send it */
689 { WM_NCACTIVATE, sent|wparam|optional, 0 },
690 { WM_ACTIVATE, sent|wparam|optional, 0 },
691 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
692 { HCBT_SETFOCUS, hook|optional },
693 { WM_KILLFOCUS, sent|wparam|optional, 0 },
694 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
695 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
696 { 0 }
697 };
698 /* DestroyWindow for a visible overlapped window */
699 static const struct message WmDestroyOverlappedSeq[] = {
700 { HCBT_DESTROYWND, hook },
701 { 0x0090, sent|optional },
702 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
703 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
704 { 0x0090, sent|optional },
705 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
706 { WM_NCACTIVATE, sent|optional|wparam, 0 },
707 { WM_ACTIVATE, sent|optional },
708 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
709 { WM_KILLFOCUS, sent|optional|wparam, 0 },
710 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
711 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
712 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
713 { WM_DESTROY, sent },
714 { WM_NCDESTROY, sent },
715 { 0 }
716 };
717 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
718 static const struct message WmCreateMaxPopupSeq[] = {
719 { HCBT_CREATEWND, hook },
720 { WM_NCCREATE, sent },
721 { WM_NCCALCSIZE, sent|wparam, 0 },
722 { WM_CREATE, sent },
723 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
724 { WM_SIZE, sent|wparam, SIZE_RESTORED },
725 { WM_MOVE, sent },
726 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
727 { WM_GETMINMAXINFO, sent },
728 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
729 { WM_NCCALCSIZE, sent|wparam, TRUE },
730 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
731 { WM_MOVE, sent|defwinproc },
732 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
733 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
734 { WM_SHOWWINDOW, sent|wparam, 1 },
735 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
736 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
737 { HCBT_ACTIVATE, hook },
738 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
739 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
740 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
741 { WM_NCPAINT, sent|wparam|optional, 1 },
742 { WM_ERASEBKGND, sent|optional },
743 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
744 { WM_ACTIVATEAPP, sent|wparam, 1 },
745 { WM_NCACTIVATE, sent },
746 { WM_ACTIVATE, sent|wparam, 1 },
747 { HCBT_SETFOCUS, hook },
748 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
749 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
750 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
751 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
752 { WM_GETTEXT, sent|optional },
753 { WM_SYNCPAINT, sent|wparam|optional, 4 },
754 { WM_NCPAINT, sent|wparam|optional, 1 },
755 { WM_ERASEBKGND, sent|optional },
756 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
757 { WM_ERASEBKGND, sent|defwinproc|optional },
758 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
759 { 0 }
760 };
761 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
762 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
763 { HCBT_CREATEWND, hook },
764 { WM_NCCREATE, sent },
765 { WM_NCCALCSIZE, sent|wparam, 0 },
766 { WM_CREATE, sent },
767 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
768 { WM_SIZE, sent|wparam, SIZE_RESTORED },
769 { WM_MOVE, sent },
770 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
771 { WM_GETMINMAXINFO, sent },
772 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
773 { WM_NCCALCSIZE, sent|wparam, TRUE },
774 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
775 { WM_MOVE, sent|defwinproc },
776 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
777 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
778 { 0 }
779 };
780 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
781 static const struct message WmShowMaxPopupResizedSeq_todo[] = {
782 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
783 { WM_GETMINMAXINFO, sent },
784 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
785 { WM_NCCALCSIZE, sent|wparam, TRUE },
786 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
787 { HCBT_ACTIVATE, hook },
788 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
789 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
790 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
791 { WM_NCPAINT, sent|wparam|optional, 1 },
792 { WM_ERASEBKGND, sent|optional },
793 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
794 { WM_ACTIVATEAPP, sent|wparam, 1 },
795 { WM_NCACTIVATE, sent },
796 { WM_ACTIVATE, sent|wparam, 1 },
797 { HCBT_SETFOCUS, hook },
798 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
799 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
800 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
801 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
802 { WM_GETTEXT, sent|optional },
803 { WM_NCPAINT, sent|wparam|optional, 1 },
804 { WM_ERASEBKGND, sent|optional },
805 { WM_WINDOWPOSCHANGED, sent },
806 /* WinNT4.0 sends WM_MOVE */
807 { WM_MOVE, sent|defwinproc|optional },
808 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
809 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
810 { 0 }
811 };
812 static const struct message WmShowMaxPopupResizedSeq[] = {
813 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
814 { WM_GETMINMAXINFO, sent },
815 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
816 { WM_NCCALCSIZE, sent|wparam, TRUE },
817 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
818 { HCBT_ACTIVATE, hook },
819 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
820 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
821 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
822 { WM_NCPAINT, sent|wparam|optional, 1 },
823 { WM_ERASEBKGND, sent|optional },
824 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
825 { WM_ACTIVATEAPP, sent|wparam, 1 },
826 { WM_NCACTIVATE, sent },
827 { WM_ACTIVATE, sent|wparam, 1 },
828 { HCBT_SETFOCUS, hook },
829 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
830 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
831 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
832 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
833 { WM_GETTEXT, sent|optional },
834 { WM_NCPAINT, sent|optional }, /* We'll check WM_NCPAINT behaviour in another test */
835 { WM_ERASEBKGND, sent|optional },
836 { WM_WINDOWPOSCHANGED, sent },
837 /* WinNT4.0 sends WM_MOVE */
838 { WM_MOVE, sent|defwinproc|optional },
839 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
840 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
841 { 0 }
842 };
843 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
844 static const struct message WmShowMaxPopupSeq[] = {
845 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
846 { WM_GETMINMAXINFO, sent },
847 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
848 { WM_NCCALCSIZE, sent|wparam, TRUE },
849 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
850 { HCBT_ACTIVATE, hook },
851 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
852 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
853 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
854 { WM_NCPAINT, sent|wparam|optional, 1 },
855 { WM_ERASEBKGND, sent|optional },
856 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
857 { WM_ACTIVATEAPP, sent|wparam, 1 },
858 { WM_NCACTIVATE, sent },
859 { WM_ACTIVATE, sent|wparam, 1 },
860 { HCBT_SETFOCUS, hook },
861 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
862 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
863 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
864 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
865 { WM_GETTEXT, sent|optional },
866 { WM_SYNCPAINT, sent|wparam|optional, 4 },
867 { WM_NCPAINT, sent|wparam|optional, 1 },
868 { WM_ERASEBKGND, sent|optional },
869 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
870 { WM_ERASEBKGND, sent|defwinproc|optional },
871 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
872 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
873 { 0 }
874 };
875 /* CreateWindow(WS_VISIBLE) for popup window */
876 static const struct message WmCreatePopupSeq[] = {
877 { HCBT_CREATEWND, hook },
878 { WM_NCCREATE, sent },
879 { WM_NCCALCSIZE, sent|wparam, 0 },
880 { WM_CREATE, sent },
881 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
882 { WM_SIZE, sent|wparam, SIZE_RESTORED },
883 { WM_MOVE, sent },
884 { WM_SHOWWINDOW, sent|wparam, 1 },
885 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
886 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
887 { HCBT_ACTIVATE, hook },
888 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
889 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
890 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
891 { WM_NCPAINT, sent|wparam|optional, 1 },
892 { WM_ERASEBKGND, sent|optional },
893 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
894 { WM_ACTIVATEAPP, sent|wparam, 1 },
895 { WM_NCACTIVATE, sent },
896 { WM_ACTIVATE, sent|wparam, 1 },
897 { HCBT_SETFOCUS, hook },
898 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
899 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
900 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
901 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
902 { WM_GETTEXT, sent|optional },
903 { WM_SYNCPAINT, sent|wparam|optional, 4 },
904 { WM_NCPAINT, sent|wparam|optional, 1 },
905 { WM_ERASEBKGND, sent|optional },
906 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
907 { 0 }
908 };
909 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
910 static const struct message WmShowVisMaxPopupSeq[] = {
911 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
912 { WM_GETMINMAXINFO, sent },
913 { WM_GETTEXT, sent|optional },
914 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
915 { WM_GETTEXT, sent|optional },
916 { WM_NCCALCSIZE, sent|wparam, TRUE },
917 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
918 { WM_NCPAINT, sent|wparam|optional, 1 },
919 { WM_ERASEBKGND, sent|optional },
920 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
921 { WM_MOVE, sent|defwinproc },
922 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
923 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
924 { 0 }
925 };
926 /* CreateWindow (for a child popup window, not initially visible) */
927 static const struct message WmCreateChildPopupSeq[] = {
928 { HCBT_CREATEWND, hook },
929 { WM_NCCREATE, sent },
930 { WM_NCCALCSIZE, sent|wparam, 0 },
931 { WM_CREATE, sent },
932 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
933 { WM_SIZE, sent|wparam, SIZE_RESTORED },
934 { WM_MOVE, sent },
935 { 0 }
936 };
937 /* CreateWindow (for a popup window, not initially visible,
938 * which sets WS_VISIBLE in WM_CREATE handler)
939 */
940 static const struct message WmCreateInvisiblePopupSeq[] = {
941 { HCBT_CREATEWND, hook },
942 { WM_NCCREATE, sent },
943 { WM_NCCALCSIZE, sent|wparam, 0 },
944 { WM_CREATE, sent },
945 { WM_STYLECHANGING, sent },
946 { WM_STYLECHANGED, sent },
947 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
948 { WM_SIZE, sent|wparam, SIZE_RESTORED },
949 { WM_MOVE, sent },
950 { 0 }
951 };
952 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
953 * for a popup window with WS_VISIBLE style set
954 */
955 static const struct message WmShowVisiblePopupSeq_2[] = {
956 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
957 { 0 }
958 };
959 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
960 * for a popup window with WS_VISIBLE style set
961 */
962 static const struct message WmShowVisiblePopupSeq_3[] = {
963 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
964 { HCBT_ACTIVATE, hook },
965 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
966 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
967 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
968 { WM_NCACTIVATE, sent },
969 { WM_ACTIVATE, sent|wparam, 1 },
970 { HCBT_SETFOCUS, hook },
971 { WM_KILLFOCUS, sent|parent },
972 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
973 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
974 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
975 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
976 { WM_SETFOCUS, sent|defwinproc },
977 { WM_GETTEXT, sent|optional },
978 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
979 { 0 }
980 };
981 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
982 */
983 static const struct message WmShowPopupExtremeLocationSeq[] = {
984 { HCBT_CREATEWND, hook },
985 { WM_NCCREATE, sent },
986 { WM_NCCALCSIZE, sent|wparam, 0 },
987 { WM_CREATE, sent },
988 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
989 { WM_SIZE, sent|wparam, SIZE_RESTORED },
990 { WM_MOVE, sent },
991 { WM_SHOWWINDOW, sent|wparam, 1 },
992 { WM_WINDOWPOSCHANGING, sent },
993 { HCBT_ACTIVATE, hook },
994 { WM_WINDOWPOSCHANGING, sent|optional },
995 { WM_QUERYNEWPALETTE, sent|optional },
996 { WM_ACTIVATEAPP, sent },
997 { WM_NCACTIVATE, sent },
998 { WM_ACTIVATE, sent },
999 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1000 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1001 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1002 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1003 { HCBT_SETFOCUS, hook },
1004 { WM_SETFOCUS, sent|defwinproc },
1005 { WM_NCPAINT, sent|wparam, 1 },
1006 { WM_ERASEBKGND, sent },
1007 { WM_WINDOWPOSCHANGED, sent },
1008 /* occasionally received on test machines */
1009 { WM_NCPAINT, sent|optional },
1010 { WM_ERASEBKGND, sent|optional },
1011 { 0 }
1012 };
1013 /* CreateWindow (for a popup window with WS_VISIBLE style set)
1014 */
1015 static const struct message WmShowPopupFirstDrawSeq_1[] = {
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 { WM_SHOWWINDOW, sent|wparam, 1 },
1024 { WM_WINDOWPOSCHANGING, sent },
1025 { HCBT_ACTIVATE, hook },
1026 { WM_WINDOWPOSCHANGING, sent|optional },
1027 { WM_QUERYNEWPALETTE, sent|optional },
1028 { WM_ACTIVATEAPP, sent },
1029 { WM_NCACTIVATE, sent },
1030 { WM_ACTIVATE, sent },
1031 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1032 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1033 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1034 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1035 { HCBT_SETFOCUS, hook },
1036 { WM_SETFOCUS, sent|defwinproc },
1037 { WM_NCPAINT, sent|wparam, 1 },
1038 { WM_ERASEBKGND, sent },
1039 { WM_WINDOWPOSCHANGED, sent },
1040 { WM_PAINT, sent },
1041 /* occasionally received on test machines */
1042 { WM_NCPAINT, sent|beginpaint|optional },
1043 { WM_ERASEBKGND, sent|beginpaint|optional },
1044 { 0 }
1045 };
1046 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1047 */
1048 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1049 { HCBT_CREATEWND, hook },
1050 { WM_NCCREATE, sent },
1051 { WM_NCCALCSIZE, sent|wparam, 0 },
1052 { WM_CREATE, sent },
1053 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1054 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1055 { WM_MOVE, sent },
1056 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1057 { WM_GETMINMAXINFO, sent },
1058 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1059 { WM_NCCALCSIZE, sent|wparam, TRUE },
1060 { HCBT_ACTIVATE, hook },
1061 { WM_WINDOWPOSCHANGING, sent|optional },
1062 { WM_NCPAINT, sent|optional|wparam, 1 },
1063 { WM_ERASEBKGND, sent|optional },
1064 { WM_WINDOWPOSCHANGED, sent|optional },
1065 { WM_QUERYNEWPALETTE, sent|optional },
1066 { WM_ACTIVATEAPP, sent },
1067 { WM_NCACTIVATE, sent },
1068 { WM_ACTIVATE, sent },
1069 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1070 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1071 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1072 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1073 { HCBT_SETFOCUS, hook },
1074 { WM_SETFOCUS, sent|defwinproc },
1075 { WM_NCPAINT, sent|wparam, 1 },
1076 { WM_ERASEBKGND, sent },
1077 { WM_WINDOWPOSCHANGED, sent|optional },
1078 { WM_MOVE, sent|defwinproc },
1079 { WM_SIZE, sent|defwinproc, 0 },
1080 { WM_PAINT, sent},
1081 /* occasionally received on test machines */
1082 { WM_NCPAINT, sent|beginpaint|optional },
1083 { WM_ERASEBKGND, sent|beginpaint|optional },
1084 { 0 }
1085 };
1086 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1087 { HCBT_CREATEWND, hook },
1088 { WM_NCCREATE, sent },
1089 { WM_NCCALCSIZE, sent|wparam, 0 },
1090 { WM_CREATE, sent },
1091 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1092 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1093 { WM_MOVE, sent },
1094 { WM_WINDOWPOSCHANGING, sent },
1095 { HCBT_ACTIVATE, hook },
1096 { WM_WINDOWPOSCHANGING, sent|optional },
1097 { WM_QUERYNEWPALETTE, sent|optional },
1098 { WM_ACTIVATEAPP, sent },
1099 { WM_NCACTIVATE, sent },
1100 { WM_ACTIVATE, sent },
1101 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1102 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1103 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1104 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1105 { HCBT_SETFOCUS, hook },
1106 { WM_SETFOCUS, sent|defwinproc },
1107 { WM_NCPAINT, sent|wparam, 1 },
1108 { WM_ERASEBKGND, sent },
1109 { WM_WINDOWPOSCHANGED, sent },
1110 { WM_MOVE, sent|defwinproc },
1111 { 0 }
1112 };
1113 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1114 { HCBT_CREATEWND, hook },
1115 { WM_NCCREATE, sent },
1116 { WM_NCCALCSIZE, sent|wparam, 0 },
1117 { WM_CREATE, sent },
1118 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1119 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1120 { WM_MOVE, sent },
1121 { WM_WINDOWPOSCHANGING, sent },
1122 { HCBT_ACTIVATE, hook },
1123 { WM_QUERYNEWPALETTE, sent|optional },
1124 { WM_WINDOWPOSCHANGING, sent|optional },
1125 { WM_ACTIVATEAPP, sent },
1126 { WM_NCACTIVATE, sent },
1127 { WM_ACTIVATE, sent },
1128 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1129 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1130 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1131 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1132 { HCBT_SETFOCUS, hook },
1133 { WM_SETFOCUS, sent|defwinproc },
1134 { WM_WINDOWPOSCHANGED, sent },
1135 { WM_MOVE, sent|defwinproc },
1136 { 0 }
1137 };
1138 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1139 { HCBT_CREATEWND, hook },
1140 { WM_NCCREATE, sent },
1141 { WM_NCCALCSIZE, sent|wparam, 0 },
1142 { WM_CREATE, sent },
1143 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1144 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1145 { WM_MOVE, sent },
1146 { HCBT_ACTIVATE, hook|optional },
1147 /* Probably shouldn't happen, but not part of this test */
1148 { WM_QUERYNEWPALETTE, sent|optional },
1149 { WM_ACTIVATEAPP, sent|optional },
1150 { WM_NCACTIVATE, sent|optional },
1151 { WM_ACTIVATE, sent|optional },
1152 { HCBT_SETFOCUS, hook|optional },
1153 { WM_SETFOCUS, sent|defwinproc|optional },
1154 { 0 }
1155 };
1156 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1157 { HCBT_CREATEWND, hook },
1158 { WM_NCCREATE, sent },
1159 { WM_NCCALCSIZE, sent|wparam, 0 },
1160 { WM_CREATE, sent },
1161 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1162 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1163 { WM_MOVE, sent },
1164 { WM_WINDOWPOSCHANGING, sent },
1165 { HCBT_ACTIVATE, hook },
1166 { WM_WINDOWPOSCHANGING, sent|optional },
1167 { WM_QUERYNEWPALETTE, sent|optional },
1168 { WM_ACTIVATEAPP, sent },
1169 { WM_NCACTIVATE, sent },
1170 { WM_ACTIVATE, sent },
1171 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1172 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1173 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1174 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1175 { HCBT_SETFOCUS, hook },
1176 { WM_SETFOCUS, sent|defwinproc },
1177 { WM_NCPAINT, sent|wparam, 1 },
1178 { WM_ERASEBKGND, sent },
1179 { WM_WINDOWPOSCHANGED, sent },
1180 { 0 }
1181 };
1182 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1183 { HCBT_CREATEWND, hook },
1184 { WM_NCCREATE, sent },
1185 { WM_NCCALCSIZE, sent|wparam, 0 },
1186 { WM_CREATE, sent },
1187 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1188 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1189 { WM_MOVE, sent },
1190 { WM_WINDOWPOSCHANGING, sent },
1191 { HCBT_ACTIVATE, hook },
1192 { WM_WINDOWPOSCHANGING, sent|optional },
1193 { WM_QUERYNEWPALETTE, sent|optional },
1194 { WM_ACTIVATEAPP, sent },
1195 { WM_NCACTIVATE, sent },
1196 { WM_ACTIVATE, sent },
1197 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1198 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1199 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1200 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1201 { HCBT_SETFOCUS, hook },
1202 { WM_SETFOCUS, sent|defwinproc },
1203 { WM_WINDOWPOSCHANGED, sent },
1204 { 0 }
1205 };
1206 static const struct message WmFirstDrawChildSeq1[] = {
1207 { 0 }
1208 };
1209 static const struct message WmFirstDrawChildSeq2[] = {
1210 { WM_NCPAINT, sent|wparam, 1 },
1211 { WM_ERASEBKGND, sent },
1212 /* occasionally received on test machines */
1213 { WM_NCPAINT, sent|optional },
1214 { WM_ERASEBKGND, sent|optional },
1215 { 0 }
1216 };
1217 /* CreateWindow (for child window, not initially visible) */
1218 static const struct message WmCreateChildSeq[] = {
1219 { HCBT_CREATEWND, hook },
1220 { WM_NCCREATE, sent },
1221 /* child is inserted into parent's child list after WM_NCCREATE returns */
1222 { WM_NCCALCSIZE, sent|wparam, 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 { 0 }
1229 };
1230 /* CreateWindow (for maximized child window, not initially visible) */
1231 static const struct message WmCreateMaximizedChildSeq[] = {
1232 { HCBT_CREATEWND, hook },
1233 { WM_NCCREATE, sent },
1234 { WM_NCCALCSIZE, sent|wparam, 0 },
1235 { WM_CREATE, sent },
1236 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1237 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1238 { WM_MOVE, sent },
1239 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1240 { WM_GETMINMAXINFO, sent },
1241 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1242 { WM_NCCALCSIZE, sent|wparam, 1 },
1243 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1244 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1245 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1246 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1247 { 0 }
1248 };
1249 /* CreateWindow (for a child window, initially visible) */
1250 static const struct message WmCreateVisibleChildSeq[] = {
1251 { HCBT_CREATEWND, hook },
1252 { WM_NCCREATE, sent },
1253 /* child is inserted into parent's child list after WM_NCCREATE returns */
1254 { WM_NCCALCSIZE, sent|wparam, 0 },
1255 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1256 { WM_CREATE, sent },
1257 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1258 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1259 { WM_MOVE, sent },
1260 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1261 { WM_SHOWWINDOW, sent|wparam, 1 },
1262 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1263 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1264 { WM_ERASEBKGND, sent|parent|optional },
1265 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1266 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1267 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1268 { 0 }
1269 };
1270 /* ShowWindow(SW_SHOW) for a not visible child window */
1271 static const struct message WmShowChildSeq[] = {
1272 { WM_SHOWWINDOW, sent|wparam, 1 },
1273 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1274 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1275 { WM_ERASEBKGND, sent|parent|optional },
1276 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1277 { 0 }
1278 };
1279 /* ShowWindow(SW_HIDE) for a visible child window */
1280 static const struct message WmHideChildSeq[] = {
1281 { WM_SHOWWINDOW, sent|wparam, 0 },
1282 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1283 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1284 { WM_ERASEBKGND, sent|parent|optional },
1285 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1286 { 0 }
1287 };
1288 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1289 static const struct message WmHideChildSeq2[] = {
1290 { WM_SHOWWINDOW, sent|wparam, 0 },
1291 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1292 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1293 { WM_ERASEBKGND, sent|parent|optional },
1294 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1295 { 0 }
1296 };
1297 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1298 * for a not visible child window
1299 */
1300 static const struct message WmShowChildSeq_2[] = {
1301 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1302 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1303 { WM_CHILDACTIVATE, sent },
1304 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1305 { 0 }
1306 };
1307 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1308 * for a not visible child window
1309 */
1310 static const struct message WmShowChildSeq_3[] = {
1311 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1312 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1313 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1314 { 0 }
1315 };
1316 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1317 * for a visible child window with a caption
1318 */
1319 static const struct message WmShowChildSeq_4[] = {
1320 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1321 { WM_CHILDACTIVATE, sent },
1322 { 0 }
1323 };
1324 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1325 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1326 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1327 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1328 { WM_NCCALCSIZE, sent|wparam, 1 },
1329 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1330 { WM_CHILDACTIVATE, sent|optional },
1331 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1332 { WM_MOVE, sent|defwinproc },
1333 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1334 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1335 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1336 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1337 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1338 { WM_GETTEXT, sent|optional },
1339 { 0 }
1340 };
1341 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1342 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1343 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1344 { 0 }
1345 };
1346 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1347 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1348 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1349 { WM_GETMINMAXINFO, sent },
1350 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1351 { WM_NCCALCSIZE, sent|wparam, 1 },
1352 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1353 { WM_CHILDACTIVATE, sent },
1354 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1355 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1356 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1357 { 0 }
1358 };
1359 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1360 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1361 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1362 { 0 }
1363 };
1364 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1365 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1366 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1367 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1368 { WM_NCCALCSIZE, sent|wparam, 1 },
1369 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1370 { WM_CHILDACTIVATE, sent },
1371 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1372 { WM_MOVE, sent|defwinproc },
1373 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1374 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1375 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1376 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1377 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1378 { WM_GETTEXT, sent|optional },
1379 { 0 }
1380 };
1381 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1382 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1383 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1384 { 0 }
1385 };
1386 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1387 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1388 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1389 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1390 { WM_NCCALCSIZE, sent|wparam, 1 },
1391 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1392 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1393 { WM_MOVE, sent|defwinproc },
1394 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1395 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1396 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1397 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1398 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1399 { WM_GETTEXT, sent|optional },
1400 { 0 }
1401 };
1402 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1403 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1404 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1405 { 0 }
1406 };
1407 /* ShowWindow(SW_SHOW) for child with invisible parent */
1408 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1409 { WM_SHOWWINDOW, sent|wparam, 1 },
1410 { 0 }
1411 };
1412 /* ShowWindow(SW_HIDE) for child with invisible parent */
1413 static const struct message WmHideChildInvisibleParentSeq[] = {
1414 { WM_SHOWWINDOW, sent|wparam, 0 },
1415 { 0 }
1416 };
1417 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1418 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1419 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1420 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1421 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1422 { 0 }
1423 };
1424 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1425 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1426 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1427 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1428 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1429 { 0 }
1430 };
1431 /* DestroyWindow for a visible child window */
1432 static const struct message WmDestroyChildSeq[] = {
1433 { HCBT_DESTROYWND, hook },
1434 { 0x0090, sent|optional },
1435 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1436 { WM_SHOWWINDOW, sent|wparam, 0 },
1437 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1438 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1439 { WM_ERASEBKGND, sent|parent|optional },
1440 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1441 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1442 { WM_KILLFOCUS, sent },
1443 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1444 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1445 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1446 { WM_SETFOCUS, sent|parent },
1447 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1448 { WM_DESTROY, sent },
1449 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1450 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1451 { WM_NCDESTROY, sent },
1452 { 0 }
1453 };
1454 /* visible child window destroyed by thread exit */
1455 static const struct message WmExitThreadSeq[] = {
1456 { WM_NCDESTROY, sent }, /* actually in grandchild */
1457 { WM_PAINT, sent|parent },
1458 { WM_ERASEBKGND, sent|parent|beginpaint },
1459 { 0 }
1460 };
1461 /* DestroyWindow for a visible child window with invisible parent */
1462 static const struct message WmDestroyInvisibleChildSeq[] = {
1463 { HCBT_DESTROYWND, hook },
1464 { 0x0090, sent|optional },
1465 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1466 { WM_SHOWWINDOW, sent|wparam, 0 },
1467 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1468 { WM_DESTROY, sent },
1469 { WM_NCDESTROY, sent },
1470 { 0 }
1471 };
1472 /* Resizing child window with MoveWindow (32) */
1473 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1474 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1475 { WM_NCCALCSIZE, sent|wparam, 1 },
1476 { WM_ERASEBKGND, sent|parent|optional },
1477 { WM_ERASEBKGND, sent|optional },
1478 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1479 { WM_MOVE, sent|defwinproc },
1480 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1481 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1482 { 0 }
1483 };
1484 /* Creation of a custom dialog (32) */
1485 static const struct message WmCreateCustomDialogSeq[] = {
1486 { HCBT_CREATEWND, hook },
1487 { WM_GETMINMAXINFO, sent },
1488 { WM_NCCREATE, sent },
1489 { WM_NCCALCSIZE, sent|wparam, 0 },
1490 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1491 { WM_CREATE, sent },
1492 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1493 { WM_NOTIFYFORMAT, sent|optional },
1494 { WM_QUERYUISTATE, sent|optional },
1495 { WM_WINDOWPOSCHANGING, sent|optional },
1496 { WM_GETMINMAXINFO, sent|optional },
1497 { WM_NCCALCSIZE, sent|optional },
1498 { WM_WINDOWPOSCHANGED, sent|optional },
1499 { WM_SHOWWINDOW, sent|wparam, 1 },
1500 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1501 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1502 { HCBT_ACTIVATE, hook },
1503 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1504
1505
1506 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1507
1508 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1509
1510 { WM_NCACTIVATE, sent },
1511 { WM_GETTEXT, sent|optional|defwinproc },
1512 { WM_GETTEXT, sent|optional|defwinproc },
1513 { WM_GETTEXT, sent|optional|defwinproc },
1514 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1515 { WM_ACTIVATE, sent|wparam, 1 },
1516 { WM_GETTEXT, sent|optional },
1517 { WM_KILLFOCUS, sent|parent },
1518 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1519 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1520 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1521 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1522 { WM_SETFOCUS, sent },
1523 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1524 { WM_NCPAINT, sent|wparam, 1 },
1525 { WM_GETTEXT, sent|optional|defwinproc },
1526 { WM_GETTEXT, sent|optional|defwinproc },
1527 { WM_ERASEBKGND, sent },
1528 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1529 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1530 { WM_GETTEXT, sent|optional },
1531 { WM_GETTEXT, sent|optional },
1532 { WM_NCCALCSIZE, sent|optional },
1533 { WM_NCPAINT, sent|optional },
1534 { WM_GETTEXT, sent|optional|defwinproc },
1535 { WM_GETTEXT, sent|optional|defwinproc },
1536 { WM_ERASEBKGND, sent|optional },
1537 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1538 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1539 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1540 { WM_MOVE, sent },
1541 { 0 }
1542 };
1543 /* Calling EndDialog for a custom dialog (32) */
1544 static const struct message WmEndCustomDialogSeq[] = {
1545 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1546 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1547 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1548 { WM_GETTEXT, sent|optional },
1549 { HCBT_ACTIVATE, hook },
1550 { WM_NCACTIVATE, sent|wparam, 0 },
1551 { WM_GETTEXT, sent|optional|defwinproc },
1552 { WM_GETTEXT, sent|optional|defwinproc },
1553 { WM_ACTIVATE, sent|wparam, 0 },
1554 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1555 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1556 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1557 { WM_GETTEXT, sent|optional|defwinproc },
1558 { WM_GETTEXT, sent|optional|defwinproc },
1559 { HCBT_SETFOCUS, hook },
1560 { WM_KILLFOCUS, sent },
1561 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1562 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1563 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1564 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1565 { WM_SETFOCUS, sent|parent|defwinproc },
1566 { 0 }
1567 };
1568 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1569 static const struct message WmShowCustomDialogSeq[] = {
1570 { WM_SHOWWINDOW, sent|wparam, 1 },
1571 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1572 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1573 { HCBT_ACTIVATE, hook },
1574 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1575
1576 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1577
1578 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1579 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1580 { WM_NCACTIVATE, sent },
1581 { WM_ACTIVATE, sent|wparam, 1 },
1582 { WM_GETTEXT, sent|optional },
1583
1584 { WM_KILLFOCUS, sent|parent },
1585 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1586 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1587 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1588 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1589 { WM_SETFOCUS, sent },
1590 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1591 { WM_NCPAINT, sent|wparam, 1 },
1592 { WM_ERASEBKGND, sent },
1593 { WM_CTLCOLORDLG, sent|defwinproc },
1594 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1595 { 0 }
1596 };
1597 /* Creation and destruction of a modal dialog (32) */
1598 static const struct message WmModalDialogSeq[] = {
1599 { WM_CANCELMODE, sent|parent },
1600 { HCBT_SETFOCUS, hook },
1601 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1602 { WM_KILLFOCUS, sent|parent },
1603 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1604 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1605 { WM_ENABLE, sent|parent|wparam, 0 },
1606 { HCBT_CREATEWND, hook },
1607 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1608 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1609 { WM_SETFONT, sent },
1610 { WM_INITDIALOG, sent },
1611 { WM_CHANGEUISTATE, sent|optional },
1612 { WM_UPDATEUISTATE, sent|optional },
1613 { WM_SHOWWINDOW, sent },
1614 { HCBT_ACTIVATE, hook },
1615 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1616 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1617 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1618 { WM_NCACTIVATE, sent },
1619 { WM_GETTEXT, sent|optional },
1620 { WM_ACTIVATE, sent|wparam, 1 },
1621 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1622 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1623 { WM_NCPAINT, sent|optional },
1624 { WM_GETTEXT, sent|optional },
1625 { WM_ERASEBKGND, sent|optional },
1626 { WM_CTLCOLORDLG, sent|optional },
1627 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1628 { WM_GETTEXT, sent|optional },
1629 { WM_NCCALCSIZE, sent|optional },
1630 { WM_NCPAINT, sent|optional },
1631 { WM_GETTEXT, sent|optional },
1632 { WM_ERASEBKGND, sent|optional },
1633 { WM_CTLCOLORDLG, sent|optional },
1634 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1635 { WM_PAINT, sent|optional },
1636 { WM_CTLCOLORBTN, sent|optional },
1637 { WM_GETTITLEBARINFOEX, sent|optional },
1638 { WM_ENTERIDLE, sent|parent|optional },
1639 { WM_ENTERIDLE, sent|parent|optional },
1640 { WM_ENTERIDLE, sent|parent|optional },
1641 { WM_ENTERIDLE, sent|parent|optional },
1642 { WM_ENTERIDLE, sent|parent|optional },
1643 { WM_ENTERIDLE, sent|parent|optional },
1644 { WM_ENTERIDLE, sent|parent|optional },
1645 { WM_ENTERIDLE, sent|parent|optional },
1646 { WM_ENTERIDLE, sent|parent|optional },
1647 { WM_ENTERIDLE, sent|parent|optional },
1648 { WM_ENTERIDLE, sent|parent|optional },
1649 { WM_ENTERIDLE, sent|parent|optional },
1650 { WM_ENTERIDLE, sent|parent|optional },
1651 { WM_ENTERIDLE, sent|parent|optional },
1652 { WM_ENTERIDLE, sent|parent|optional },
1653 { WM_ENTERIDLE, sent|parent|optional },
1654 { WM_ENTERIDLE, sent|parent|optional },
1655 { WM_ENTERIDLE, sent|parent|optional },
1656 { WM_ENTERIDLE, sent|parent|optional },
1657 { WM_ENTERIDLE, sent|parent|optional },
1658 { WM_TIMER, sent },
1659 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1660 { WM_ENABLE, sent|parent|wparam, 1 },
1661 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1662 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1663 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1664 { WM_GETTEXT, sent|optional },
1665 { HCBT_ACTIVATE, hook },
1666 { WM_NCACTIVATE, sent|wparam, 0 },
1667 { WM_GETTEXT, sent|optional },
1668 { WM_ACTIVATE, sent|wparam, 0 },
1669 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1670 { WM_WINDOWPOSCHANGING, sent|optional },
1671 { WM_WINDOWPOSCHANGED, sent|optional },
1672 { HCBT_SETFOCUS, hook },
1673 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1674 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1675 { WM_SETFOCUS, sent|parent|defwinproc },
1676 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1677 { HCBT_DESTROYWND, hook },
1678 { 0x0090, sent|optional },
1679 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1680 { WM_DESTROY, sent },
1681 { WM_NCDESTROY, sent },
1682 { 0 }
1683 };
1684 static const struct message WmModalDialogSeq_2[] = {
1685 { WM_CANCELMODE, sent },
1686 { HCBT_SETFOCUS, hook },
1687 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1688 { WM_KILLFOCUS, sent },
1689 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1690 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1691 { WM_ENABLE, sent|wparam, 0 },
1692 { HCBT_CREATEWND, hook },
1693 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1694 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1695 { WM_SETFONT, sent },
1696 { WM_INITDIALOG, sent },
1697 { WM_CHANGEUISTATE, sent|optional },
1698 { WM_UPDATEUISTATE, sent|optional },
1699 { WM_ENABLE, sent|wparam, 1 },
1700 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1701 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1702 { WM_CHANGEUISTATE, sent|optional },
1703 { WM_UPDATEUISTATE, sent|optional },
1704 { HCBT_DESTROYWND, hook },
1705 { 0x0090, sent|optional },
1706 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1707 { WM_DESTROY, sent },
1708 { WM_NCDESTROY, sent },
1709 { 0 }
1710 };
1711 /* SetMenu for NonVisible windows with size change*/
1712 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1713 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1714 { WM_NCCALCSIZE, sent|wparam, 1 },
1715 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1716 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1717 { WM_MOVE, sent|defwinproc },
1718 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1719 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1720 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1721 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1722 { WM_GETTEXT, sent|optional },
1723 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1724 { 0 }
1725 };
1726 /* SetMenu for NonVisible windows with no size change */
1727 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1728 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1729 { WM_NCCALCSIZE, sent|wparam, 1 },
1730 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1731 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1732 { 0 }
1733 };
1734 /* SetMenu for Visible windows with size change */
1735 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1736 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1737 { WM_NCCALCSIZE, sent|wparam, 1 },
1738 { 0x0093, sent|defwinproc|optional },
1739 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1740 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1741 { 0x0093, sent|defwinproc|optional },
1742 { 0x0093, sent|defwinproc|optional },
1743 { 0x0091, sent|defwinproc|optional },
1744 { 0x0092, sent|defwinproc|optional },
1745 { WM_GETTEXT, sent|defwinproc|optional },
1746 { WM_ERASEBKGND, sent|optional },
1747 { WM_ACTIVATE, sent|optional },
1748 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1749 { WM_MOVE, sent|defwinproc },
1750 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1751 { 0x0093, sent|optional },
1752 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1753 { 0x0093, sent|defwinproc|optional },
1754 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1755 { 0x0093, sent|defwinproc|optional },
1756 { 0x0093, sent|defwinproc|optional },
1757 { 0x0091, sent|defwinproc|optional },
1758 { 0x0092, sent|defwinproc|optional },
1759 { WM_ERASEBKGND, sent|optional },
1760 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1761 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1762 { 0 }
1763 };
1764 /* SetMenu for Visible windows with no size change */
1765 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1766 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1767 { WM_NCCALCSIZE, sent|wparam, 1 },
1768 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1769 { WM_GETTEXT, sent|defwinproc|optional },
1770 { WM_ERASEBKGND, sent|optional },
1771 { WM_ACTIVATE, sent|optional },
1772 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1773 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1774 { 0 }
1775 };
1776 /* DrawMenuBar for a visible window */
1777 static const struct message WmDrawMenuBarSeq[] =
1778 {
1779 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1780 { WM_NCCALCSIZE, sent|wparam, 1 },
1781 { 0x0093, sent|defwinproc|optional },
1782 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1783 { 0x0093, sent|defwinproc|optional },
1784 { 0x0093, sent|defwinproc|optional },
1785 { 0x0091, sent|defwinproc|optional },
1786 { 0x0092, sent|defwinproc|optional },
1787 { WM_GETTEXT, sent|defwinproc|optional },
1788 { WM_ERASEBKGND, sent|optional },
1789 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1790 { 0x0093, sent|optional },
1791 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1792 { 0 }
1793 };
1794
1795 static const struct message WmSetRedrawFalseSeq[] =
1796 {
1797 { WM_SETREDRAW, sent|wparam, 0 },
1798 { 0 }
1799 };
1800
1801 static const struct message WmSetRedrawTrueSeq[] =
1802 {
1803 { WM_SETREDRAW, sent|wparam, 1 },
1804 { 0 }
1805 };
1806
1807 static const struct message WmEnableWindowSeq_1[] =
1808 {
1809 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1810 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1811 { HCBT_SETFOCUS, hook|optional },
1812 { WM_KILLFOCUS, sent|optional },
1813 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1814 { 0 }
1815 };
1816
1817 static const struct message WmEnableWindowSeq_2[] =
1818 {
1819 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1820 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1821 { 0 }
1822 };
1823
1824 static const struct message WmEnableWindowSeq_3[] =
1825 {
1826 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1827 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1828 { 0 }
1829 };
1830
1831 static const struct message WmEnableWindowSeq_4[] =
1832 {
1833 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1834 { 0 }
1835 };
1836
1837 static const struct message WmGetScrollRangeSeq[] =
1838 {
1839 { SBM_GETRANGE, sent },
1840 { 0 }
1841 };
1842 static const struct message WmGetScrollInfoSeq[] =
1843 {
1844 { SBM_GETSCROLLINFO, sent },
1845 { 0 }
1846 };
1847 static const struct message WmSetScrollRangeSeq[] =
1848 {
1849 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1850 sends SBM_SETSCROLLINFO.
1851 */
1852 { SBM_SETSCROLLINFO, sent },
1853 { 0 }
1854 };
1855 /* SetScrollRange for a window without a non-client area */
1856 static const struct message WmSetScrollRangeHSeq_empty[] =
1857 {
1858 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1859 { 0 }
1860 };
1861 static const struct message WmSetScrollRangeVSeq_empty[] =
1862 {
1863 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1864 { 0 }
1865 };
1866 static const struct message WmSetScrollRangeHVSeq[] =
1867 {
1868 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1869 { WM_NCCALCSIZE, sent|wparam, 1 },
1870 { WM_GETTEXT, sent|defwinproc|optional },
1871 { WM_ERASEBKGND, sent|optional },
1872 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1873 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1874 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1875 { 0 }
1876 };
1877 /* SetScrollRange for a window with a non-client area */
1878 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1879 {
1880 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1881 { WM_NCCALCSIZE, sent|wparam, 1 },
1882 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1883 { WM_NCPAINT, sent|optional },
1884 { WM_STYLECHANGING, sent|defwinproc|optional },
1885 { WM_STYLECHANGED, sent|defwinproc|optional },
1886 { WM_STYLECHANGING, sent|defwinproc|optional },
1887 { WM_STYLECHANGED, sent|defwinproc|optional },
1888 { WM_STYLECHANGING, sent|defwinproc|optional },
1889 { WM_STYLECHANGED, sent|defwinproc|optional },
1890 { WM_STYLECHANGING, sent|defwinproc|optional },
1891 { WM_STYLECHANGED, sent|defwinproc|optional },
1892 { WM_GETTEXT, sent|defwinproc|optional },
1893 { WM_GETTEXT, sent|defwinproc|optional },
1894 { WM_ERASEBKGND, sent|optional },
1895 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1896 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1897 { WM_SIZE, sent|defwinproc|optional },
1898 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1899 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1900 { WM_GETTEXT, sent|optional },
1901 { WM_GETTEXT, sent|optional },
1902 { WM_GETTEXT, sent|optional },
1903 { WM_GETTEXT, sent|optional },
1904 { 0 }
1905 };
1906 /* test if we receive the right sequence of messages */
1907 /* after calling ShowWindow( SW_SHOWNA) */
1908 static const struct message WmSHOWNAChildInvisParInvis[] = {
1909 { WM_SHOWWINDOW, sent|wparam, 1 },
1910 { 0 }
1911 };
1912 static const struct message WmSHOWNAChildVisParInvis[] = {
1913 { WM_SHOWWINDOW, sent|wparam, 1 },
1914 { 0 }
1915 };
1916 static const struct message WmSHOWNAChildVisParVis[] = {
1917 { WM_SHOWWINDOW, sent|wparam, 1 },
1918 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1919 { 0 }
1920 };
1921 static const struct message WmSHOWNAChildInvisParVis[] = {
1922 { WM_SHOWWINDOW, sent|wparam, 1 },
1923 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1924 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1925 { WM_ERASEBKGND, sent|optional },
1926 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1927 { 0 }
1928 };
1929 static const struct message WmSHOWNATopVisible[] = {
1930 { WM_SHOWWINDOW, sent|wparam, 1 },
1931 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1932 { WM_NCPAINT, sent|wparam|optional, 1 },
1933 { WM_GETTEXT, sent|defwinproc|optional },
1934 { WM_ERASEBKGND, sent|optional },
1935 { WM_WINDOWPOSCHANGED, sent|optional },
1936 { 0 }
1937 };
1938 static const struct message WmSHOWNATopInvisible[] = {
1939 { WM_NOTIFYFORMAT, sent|optional },
1940 { WM_QUERYUISTATE, sent|optional },
1941 { WM_WINDOWPOSCHANGING, sent|optional },
1942 { WM_GETMINMAXINFO, sent|optional },
1943 { WM_NCCALCSIZE, sent|optional },
1944 { WM_WINDOWPOSCHANGED, sent|optional },
1945 { WM_SHOWWINDOW, sent|wparam, 1 },
1946 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1947 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1948 { WM_NCPAINT, sent|wparam|optional, 1 },
1949 { WM_GETTEXT, sent|defwinproc|optional },
1950 { WM_ERASEBKGND, sent|optional },
1951 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1952 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1953 { WM_NCPAINT, sent|wparam|optional, 1 },
1954 { WM_ERASEBKGND, sent|optional },
1955 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1956 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1957 { WM_MOVE, sent },
1958 { 0 }
1959 };
1960
1961 static const struct message WmTrackPopupMenu[] = {
1962 { HCBT_CREATEWND, hook },
1963 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1964 { WM_INITMENU, sent|lparam, 0, 0 },
1965 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1966 { 0x0093, sent|optional },
1967 { 0x0094, sent|optional },
1968 { 0x0094, sent|optional },
1969 { WM_ENTERIDLE, sent|wparam, 2 },
1970 { WM_CAPTURECHANGED, sent },
1971 { HCBT_DESTROYWND, hook },
1972 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1973 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1974 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1975 { 0 }
1976 };
1977
1978 static const struct message WmTrackPopupMenuEsc[] = {
1979 { 0 }
1980 };
1981
1982 static const struct message WmTrackPopupMenuCapture[] = {
1983 { HCBT_CREATEWND, hook },
1984 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1985 { WM_CAPTURECHANGED, sent },
1986 { WM_INITMENU, sent|lparam, 0, 0 },
1987 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1988 { 0x0093, sent|optional },
1989 { 0x0094, sent|optional },
1990 { 0x0094, sent|optional },
1991 { WM_ENTERIDLE, sent|wparam, 2 },
1992 { WM_CAPTURECHANGED, sent },
1993 { HCBT_DESTROYWND, hook },
1994 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1995 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1996 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1997 { 0 }
1998 };
1999
2000 static const struct message WmTrackPopupMenuEmpty[] = {
2001 { HCBT_CREATEWND, hook },
2002 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2003 { WM_INITMENU, sent|lparam, 0, 0 },
2004 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2005 { 0x0093, sent|optional },
2006 { 0x0094, sent|optional },
2007 { 0x0094, sent|optional },
2008 { WM_CAPTURECHANGED, sent },
2009 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2010 { HCBT_DESTROYWND, hook },
2011 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2012 { 0 }
2013 };
2014
2015 static const struct message WmTrackPopupMenuAbort[] = {
2016 { HCBT_CREATEWND, hook },
2017 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2018 { WM_INITMENU, sent|lparam, 0, 0 },
2019 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2020 { 0x0093, sent|optional },
2021 { 0x0094, sent|optional },
2022 { 0x0094, sent|optional },
2023 { WM_CAPTURECHANGED, sent },
2024 { HCBT_DESTROYWND, hook },
2025 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2026 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2027 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2028 { 0 }
2029 };
2030
2031 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2032 static int sequence_cnt, sequence_size;
2033 static struct recvd_message* sequence;
2034 static int log_all_parent_messages;
2035 static CRITICAL_SECTION sequence_cs;
2036
2037 /* user32 functions */
2038 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2039 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2040 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2041 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2042 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2043 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2044 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2045 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2046 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2047 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2048 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2049 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2050 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2051 /* kernel32 functions */
2052 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2053
2054 static void init_procs(void)
2055 {
2056 HMODULE user32 = GetModuleHandleA("user32.dll");
2057 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2058
2059 #define GET_PROC(dll, func) \
2060 p ## func = (void*)GetProcAddress(dll, #func); \
2061 if(!p ## func) { \
2062 trace("GetProcAddress(%s) failed\n", #func); \
2063 }
2064
2065 GET_PROC(user32, GetAncestor)
2066 GET_PROC(user32, GetMenuInfo)
2067 GET_PROC(user32, NotifyWinEvent)
2068 GET_PROC(user32, SetMenuInfo)
2069 GET_PROC(user32, SetWinEventHook)
2070 GET_PROC(user32, TrackMouseEvent)
2071 GET_PROC(user32, UnhookWinEvent)
2072 GET_PROC(user32, GetMonitorInfoA)
2073 GET_PROC(user32, MonitorFromPoint)
2074 GET_PROC(user32, UpdateLayeredWindow)
2075 GET_PROC(user32, SetSystemTimer)
2076 GET_PROC(user32, KillSystemTimer)
2077 GET_PROC(user32, SetCoalescableTimer)
2078
2079 GET_PROC(kernel32, GetCPInfoExA)
2080
2081 #undef GET_PROC
2082 }
2083
2084 static const char *get_winpos_flags(UINT flags)
2085 {
2086 static char buffer[300];
2087
2088 buffer[0] = 0;
2089 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2090 DUMP( SWP_SHOWWINDOW );
2091 DUMP( SWP_HIDEWINDOW );
2092 DUMP( SWP_NOACTIVATE );
2093 DUMP( SWP_FRAMECHANGED );
2094 DUMP( SWP_NOCOPYBITS );
2095 DUMP( SWP_NOOWNERZORDER );
2096 DUMP( SWP_NOSENDCHANGING );
2097 DUMP( SWP_DEFERERASE );
2098 DUMP( SWP_ASYNCWINDOWPOS );
2099 DUMP( SWP_NOZORDER );
2100 DUMP( SWP_NOREDRAW );
2101 DUMP( SWP_NOSIZE );
2102 DUMP( SWP_NOMOVE );
2103 DUMP( SWP_NOCLIENTSIZE );
2104 DUMP( SWP_NOCLIENTMOVE );
2105 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2106 return buffer + 1;
2107 #undef DUMP
2108 }
2109
2110 static BOOL ignore_message( UINT message )
2111 {
2112 /* these are always ignored */
2113 return (message >= 0xc000 ||
2114 message == WM_GETICON ||
2115 message == WM_GETOBJECT ||
2116 message == WM_TIMECHANGE ||
2117 message == WM_DISPLAYCHANGE ||
2118 message == WM_DEVICECHANGE ||
2119 message == WM_DWMNCRENDERINGCHANGED);
2120 }
2121
2122 static unsigned hash_Ly_W(const WCHAR *str)
2123 {
2124 unsigned hash = 0;
2125
2126 for (; *str; str++)
2127 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2128
2129 return hash;
2130 }
2131
2132 static unsigned hash_Ly(const char *str)
2133 {
2134 unsigned hash = 0;
2135
2136 for (; *str; str++)
2137 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2138
2139 return hash;
2140 }
2141
2142 #define add_message(msg) add_message_(__LINE__,msg);
2143 static void add_message_(int line, const struct recvd_message *msg)
2144 {
2145 struct recvd_message *seq;
2146
2147 EnterCriticalSection( &sequence_cs );
2148 if (!sequence)
2149 {
2150 sequence_size = 10;
2151 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2152 }
2153 if (sequence_cnt == sequence_size)
2154 {
2155 sequence_size *= 2;
2156 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2157 }
2158 assert(sequence);
2159
2160 seq = &sequence[sequence_cnt++];
2161 seq->hwnd = msg->hwnd;
2162 seq->message = msg->message;
2163 seq->flags = msg->flags;
2164 seq->wParam = msg->wParam;
2165 seq->lParam = msg->lParam;
2166 seq->line = line;
2167 seq->descr = msg->descr;
2168 seq->output[0] = 0;
2169 LeaveCriticalSection( &sequence_cs );
2170
2171 if (msg->descr)
2172 {
2173 if (msg->flags & hook)
2174 {
2175 static const char * const CBT_code_name[10] =
2176 {
2177 "HCBT_MOVESIZE",
2178 "HCBT_MINMAX",
2179 "HCBT_QS",
2180 "HCBT_CREATEWND",
2181 "HCBT_DESTROYWND",
2182 "HCBT_ACTIVATE",
2183 "HCBT_CLICKSKIPPED",
2184 "HCBT_KEYSKIPPED",
2185 "HCBT_SYSCOMMAND",
2186 "HCBT_SETFOCUS"
2187 };
2188 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2189
2190 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2191 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2192 }
2193 else if (msg->flags & winevent_hook)
2194 {
2195 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2196 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2197 }
2198 else
2199 {
2200 switch (msg->message)
2201 {
2202 case WM_WINDOWPOSCHANGING:
2203 case WM_WINDOWPOSCHANGED:
2204 {
2205 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2206
2207 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2208 msg->descr, msg->hwnd,
2209 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2210 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2211 winpos->x, winpos->y, winpos->cx, winpos->cy,
2212 get_winpos_flags(winpos->flags) );
2213
2214 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2215 * in the high word for internal purposes
2216 */
2217 seq->wParam = winpos->flags & 0xffff;
2218 /* We are not interested in the flags that don't match under XP and Win9x */
2219 seq->wParam &= ~SWP_NOZORDER;
2220 break;
2221 }
2222
2223 case WM_DRAWITEM:
2224 {
2225 DRAW_ITEM_STRUCT di;
2226 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2227
2228 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2229 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2230 dis->itemID, dis->itemAction, dis->itemState);
2231
2232 di.u.lp = 0;
2233 di.u.item.type = dis->CtlType;
2234 di.u.item.ctl_id = dis->CtlID;
2235 if (dis->CtlType == ODT_LISTBOX ||
2236 dis->CtlType == ODT_COMBOBOX ||
2237 dis->CtlType == ODT_MENU)
2238 di.u.item.item_id = dis->itemID;
2239 di.u.item.action = dis->itemAction;
2240 di.u.item.state = dis->itemState;
2241
2242 seq->lParam = di.u.lp;
2243 break;
2244 }
2245
2246 case WM_MEASUREITEM:
2247 {
2248 MEASURE_ITEM_STRUCT mi;
2249 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2250 BOOL is_unicode_data = TRUE;
2251
2252 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2253 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2254 mis->itemID, mis->itemData);
2255
2256 if (mis->CtlType == ODT_LISTBOX)
2257 {
2258 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2259 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2260 }
2261
2262 mi.u.wp = 0;
2263 mi.u.item.CtlType = mis->CtlType;
2264 mi.u.item.CtlID = mis->CtlID;
2265 mi.u.item.itemID = mis->itemID;
2266 mi.u.item.wParam = msg->wParam;
2267 seq->wParam = mi.u.wp;
2268 if (is_unicode_data)
2269 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2270 else
2271 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2272 break;
2273 }
2274
2275 case WM_COMPAREITEM:
2276 {
2277 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2278 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2279 BOOL is_unicode_data = TRUE;
2280
2281 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2282 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2283 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2284 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2285
2286 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2287 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2288 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2289
2290 if (cis->CtlType == ODT_LISTBOX)
2291 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2292
2293 if (is_unicode_data)
2294 {
2295 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2296 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2297 }
2298 else
2299 {
2300 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2301 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2302 }
2303 break;
2304 }
2305
2306 default:
2307 if (msg->message >= 0xc000) return; /* ignore registered messages */
2308 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2309 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2310 }
2311 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2312 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2313 }
2314 }
2315 }
2316
2317 /* try to make sure pending X events have been processed before continuing */
2318 static void flush_events(void)
2319 {
2320 MSG msg;
2321 int diff = 200;
2322 int min_timeout = 100;
2323 DWORD time = GetTickCount() + diff;
2324
2325 while (diff > 0)
2326 {
2327 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2328 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2329 diff = time - GetTickCount();
2330 }
2331 }
2332
2333 static void flush_sequence(void)
2334 {
2335 EnterCriticalSection( &sequence_cs );
2336 HeapFree(GetProcessHeap(), 0, sequence);
2337 sequence = 0;
2338 sequence_cnt = sequence_size = 0;
2339 LeaveCriticalSection( &sequence_cs );
2340 }
2341
2342 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2343 {
2344 const struct recvd_message *actual = sequence;
2345 unsigned int count = 0;
2346
2347 trace_(file, line)("Failed sequence %s:\n", context );
2348 while (expected->message && actual->message)
2349 {
2350 if (actual->output[0])
2351 {
2352 if (expected->flags & hook)
2353 {
2354 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2355 count, expected->message, actual->output );
2356 }
2357 else if (expected->flags & winevent_hook)
2358 {
2359 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2360 count, expected->message, actual->output );
2361 }
2362 else if (expected->flags & kbd_hook)
2363 {
2364 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2365 count, expected->message, actual->output );
2366 }
2367 else
2368 {
2369 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2370 count, expected->message, actual->output );
2371 }
2372 }
2373
2374 if (expected->message == actual->message)
2375 {
2376 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2377 (expected->flags & optional))
2378 {
2379 /* don't match messages if their defwinproc status differs */
2380 expected++;
2381 }
2382 else
2383 {
2384 expected++;
2385 actual++;
2386 }
2387 }
2388 /* silently drop winevent messages if there is no support for them */
2389 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2390 expected++;
2391 else
2392 {
2393 expected++;
2394 actual++;
2395 }
2396 count++;
2397 }
2398
2399 /* optional trailing messages */
2400 while (expected->message && ((expected->flags & optional) ||
2401 ((expected->flags & winevent_hook) && !hEvent_hook)))
2402 {
2403 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2404 expected++;
2405 count++;
2406 }
2407
2408 if (expected->message)
2409 {
2410 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2411 return;
2412 }
2413
2414 while (actual->message && actual->output[0])
2415 {
2416 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2417 actual++;
2418 count++;
2419 }
2420 }
2421
2422 #define ok_sequence( exp, contx, todo) \
2423 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2424
2425
2426 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2427 const char *file, int line)
2428 {
2429 static const struct recvd_message end_of_sequence;
2430 const struct message *expected = expected_list;
2431 const struct recvd_message *actual;
2432 int failcount = 0, dump = 0;
2433 unsigned int count = 0;
2434
2435 add_message(&end_of_sequence);
2436
2437 actual = sequence;
2438
2439 while (expected->message && actual->message)
2440 {
2441 if (expected->message == actual->message &&
2442 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2443 {
2444 if (expected->flags & wparam)
2445 {
2446 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2447 {
2448 todo_wine {
2449 failcount ++;
2450 if (strcmp(winetest_platform, "wine")) dump++;
2451 ok_( file, line) (FALSE,
2452 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2453 context, count, expected->message, expected->wParam, actual->wParam);
2454 }
2455 }
2456 else
2457 {
2458 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2459 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2460 context, count, expected->message, expected->wParam, actual->wParam);
2461 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2462 }
2463
2464 }
2465 if (expected->flags & lparam)
2466 {
2467 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2468 {
2469 todo_wine {
2470 failcount ++;
2471 if (strcmp(winetest_platform, "wine")) dump++;
2472 ok_( file, line) (FALSE,
2473 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2474 context, count, expected->message, expected->lParam, actual->lParam);
2475 }
2476 }
2477 else
2478 {
2479 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2480 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2481 context, count, expected->message, expected->lParam, actual->lParam);
2482 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2483 }
2484 }
2485 if ((expected->flags & optional) &&
2486 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2487 {
2488 /* don't match optional messages if their defwinproc or parent status differs */
2489 expected++;
2490 count++;
2491 continue;
2492 }
2493 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2494 {
2495 todo_wine {
2496 failcount ++;
2497 if (strcmp(winetest_platform, "wine")) dump++;
2498 ok_( file, line) (FALSE,
2499 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2500 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2501 }
2502 }
2503 else
2504 {
2505 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2506 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2507 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2508 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2509 }
2510
2511 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2512 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2513 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2514 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2515
2516 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2517 "%s: %u: the msg 0x%04x should have been %s\n",
2518 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2519 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2520
2521 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2522 "%s: %u: the msg 0x%04x was expected in %s\n",
2523 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2524 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2525
2526 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2527 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2528 context, count, expected->message);
2529 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2530
2531 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2532 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2533 context, count, expected->message);
2534 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2535
2536 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2537 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2538 context, count, expected->message);
2539 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2540
2541 expected++;
2542 actual++;
2543 }
2544 /* silently drop hook messages if there is no support for them */
2545 else if ((expected->flags & optional) ||
2546 ((expected->flags & hook) && !hCBT_hook) ||
2547 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2548 ((expected->flags & kbd_hook) && !hKBD_hook))
2549 expected++;
2550 else if (todo)
2551 {
2552 failcount++;
2553 todo_wine {
2554 if (strcmp(winetest_platform, "wine")) dump++;
2555 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2556 context, count, expected->message, actual->message);
2557 }
2558 goto done;
2559 }
2560 else
2561 {
2562 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2563 context, count, expected->message, actual->message);
2564 dump++;
2565 expected++;
2566 actual++;
2567 }
2568 count++;
2569 }
2570
2571 /* skip all optional trailing messages */
2572 while (expected->message && ((expected->flags & optional) ||
2573 ((expected->flags & hook) && !hCBT_hook) ||
2574 ((expected->flags & winevent_hook) && !hEvent_hook)))
2575 expected++;
2576
2577 if (todo)
2578 {
2579 todo_wine {
2580 if (expected->message || actual->message) {
2581 failcount++;
2582 if (strcmp(winetest_platform, "wine")) dump++;
2583 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2584 context, count, expected->message, actual->message);
2585 }
2586 }
2587 }
2588 else
2589 {
2590 if (expected->message || actual->message)
2591 {
2592 dump++;
2593 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2594 context, count, expected->message, actual->message);
2595 }
2596 }
2597 if( todo && !failcount) /* succeeded yet marked todo */
2598 todo_wine {
2599 if (!strcmp(winetest_platform, "wine")) dump++;
2600 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2601 }
2602
2603 done:
2604 if (dump) dump_sequence(expected_list, context, file, line);
2605 flush_sequence();
2606 }
2607
2608 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2609
2610 /******************************** MDI test **********************************/
2611
2612 /* CreateWindow for MDI frame window, initially visible */
2613 static const struct message WmCreateMDIframeSeq[] = {
2614 { HCBT_CREATEWND, hook },
2615 { WM_GETMINMAXINFO, sent },
2616 { WM_NCCREATE, sent },
2617 { WM_NCCALCSIZE, sent|wparam, 0 },
2618 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2619 { WM_CREATE, sent },
2620 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2621 { WM_NOTIFYFORMAT, sent|optional },
2622 { WM_QUERYUISTATE, sent|optional },
2623 { WM_WINDOWPOSCHANGING, sent|optional },
2624 { WM_GETMINMAXINFO, sent|optional },
2625 { WM_NCCALCSIZE, sent|optional },
2626 { WM_WINDOWPOSCHANGED, sent|optional },
2627 { WM_SHOWWINDOW, sent|wparam, 1 },
2628 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2629 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2630 { HCBT_ACTIVATE, hook },
2631 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2632 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2633 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2634 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2635 { WM_NCACTIVATE, sent },
2636 { WM_GETTEXT, sent|defwinproc|optional },
2637 { WM_ACTIVATE, sent|wparam, 1 },
2638 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2639 { HCBT_SETFOCUS, hook },
2640 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2641 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2642 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2643 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2644 /* Win9x adds SWP_NOZORDER below */
2645 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2646 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2647 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2648 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2649 { WM_MOVE, sent },
2650 { 0 }
2651 };
2652 /* DestroyWindow for MDI frame window, initially visible */
2653 static const struct message WmDestroyMDIframeSeq[] = {
2654 { HCBT_DESTROYWND, hook },
2655 { 0x0090, sent|optional },
2656 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2657 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2658 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2659 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2660 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2661 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2662 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2663 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2664 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2665 { WM_DESTROY, sent },
2666 { WM_NCDESTROY, sent },
2667 { 0 }
2668 };
2669 /* CreateWindow for MDI client window, initially visible */
2670 static const struct message WmCreateMDIclientSeq[] = {
2671 { HCBT_CREATEWND, hook },
2672 { WM_NCCREATE, sent },
2673 { WM_NCCALCSIZE, sent|wparam, 0 },
2674 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2675 { WM_CREATE, sent },
2676 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2677 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2678 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2679 { WM_MOVE, sent },
2680 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2681 { WM_SHOWWINDOW, sent|wparam, 1 },
2682 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2683 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2684 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2685 { 0 }
2686 };
2687 /* ShowWindow(SW_SHOW) for MDI client window */
2688 static const struct message WmShowMDIclientSeq[] = {
2689 { WM_SHOWWINDOW, sent|wparam, 1 },
2690 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2691 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2692 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2693 { 0 }
2694 };
2695 /* ShowWindow(SW_HIDE) for MDI client window */
2696 static const struct message WmHideMDIclientSeq[] = {
2697 { WM_SHOWWINDOW, sent|wparam, 0 },
2698 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2699 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2700 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2701 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2702 { 0 }
2703 };
2704 /* DestroyWindow for MDI client window, initially visible */
2705 static const struct message WmDestroyMDIclientSeq[] = {
2706 { HCBT_DESTROYWND, hook },
2707 { 0x0090, sent|optional },
2708 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2709 { WM_SHOWWINDOW, sent|wparam, 0 },
2710 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2711 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2712 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2713 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2714 { WM_DESTROY, sent },
2715 { WM_NCDESTROY, sent },
2716 { 0 }
2717 };
2718 /* CreateWindow for MDI child window, initially visible */
2719 static const struct message WmCreateMDIchildVisibleSeq[] = {
2720 { HCBT_CREATEWND, hook },
2721 { WM_NCCREATE, sent },
2722 { WM_NCCALCSIZE, sent|wparam, 0 },
2723 { WM_CREATE, sent },
2724 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2725 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2726 { WM_MOVE, sent },
2727 /* Win2k sends wparam set to
2728 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2729 * while Win9x doesn't bother to set child window id according to
2730 * CLIENTCREATESTRUCT.idFirstChild
2731 */
2732 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2733 { WM_SHOWWINDOW, sent|wparam, 1 },
2734 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2735 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2736 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2737 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2738 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2739 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2740 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2741
2742 /* Win9x: message sequence terminates here. */
2743
2744 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2745 { HCBT_SETFOCUS, hook }, /* in MDI client */
2746 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2747 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2748 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2749 { WM_SETFOCUS, sent }, /* in MDI client */
2750 { HCBT_SETFOCUS, hook },
2751 { WM_KILLFOCUS, sent }, /* in MDI client */
2752 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2753 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2754 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2755 { WM_SETFOCUS, sent|defwinproc },
2756 { WM_MDIACTIVATE, sent|defwinproc },
2757 { 0 }
2758 };
2759 /* WM_CHILDACTIVATE sent to disabled window */
2760 static const struct message WmChildActivateDisabledWindowSeq[] = {
2761 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2762 { 0 }
2763 };
2764 /* WM_CHILDACTIVATE sent to enabled window */
2765 static const struct message WmChildActivateWindowSeq[] = {
2766 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2767 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2768 { WM_MDIACTIVATE, sent|defwinproc },
2769 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2770 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2771 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2772 { HCBT_SETFOCUS, hook },
2773 { WM_KILLFOCUS, sent|defwinproc },
2774 { WM_SETFOCUS, sent },
2775 { HCBT_SETFOCUS, hook },
2776 { WM_KILLFOCUS, sent },
2777 { WM_SETFOCUS, sent|defwinproc },
2778 { WM_MDIACTIVATE, sent|defwinproc },
2779 { 0 }
2780 };
2781 /* CreateWindow for MDI child window with invisible parent */
2782 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2783 { HCBT_CREATEWND, hook },
2784 { WM_GETMINMAXINFO, sent },
2785 { WM_NCCREATE, sent },
2786 { WM_NCCALCSIZE, sent|wparam, 0 },
2787 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2788 { WM_CREATE, sent },
2789 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2790 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2791 { WM_MOVE, sent },
2792 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2793 { WM_SHOWWINDOW, sent|wparam, 1 },
2794 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2795 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2796 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2797 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2798
2799 /* Win9x: message sequence terminates here. */
2800
2801 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2802 { HCBT_SETFOCUS, hook }, /* in MDI client */
2803 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2804 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2805 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2806 { WM_SETFOCUS, sent }, /* in MDI client */
2807 { HCBT_SETFOCUS, hook },
2808 { WM_KILLFOCUS, sent }, /* in MDI client */
2809 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2810 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2811 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2812 { WM_SETFOCUS, sent|defwinproc },
2813 { WM_MDIACTIVATE, sent|defwinproc },
2814 { 0 }
2815 };
2816 /* DestroyWindow for MDI child window, initially visible */
2817 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2818 { HCBT_DESTROYWND, hook },
2819 /* Win2k sends wparam set to
2820 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2821 * while Win9x doesn't bother to set child window id according to
2822 * CLIENTCREATESTRUCT.idFirstChild
2823 */
2824 { 0x0090, sent|optional },
2825 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2826 { WM_SHOWWINDOW, sent|wparam, 0 },
2827 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2828 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2829 { WM_ERASEBKGND, sent|parent|optional },
2830 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2831
2832 /* { WM_DESTROY, sent }
2833 * Win9x: message sequence terminates here.
2834 */
2835
2836 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2837 { WM_KILLFOCUS, sent },
2838 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2839 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2840 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2841 { WM_SETFOCUS, sent }, /* in MDI client */
2842
2843 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2844 { WM_KILLFOCUS, sent }, /* in MDI client */
2845 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2846 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2847 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2848 { WM_SETFOCUS, sent }, /* in MDI client */
2849
2850 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2851
2852 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2853 { WM_KILLFOCUS, sent },
2854 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2855 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2856 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2857 { WM_SETFOCUS, sent }, /* in MDI client */
2858
2859 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2860 { WM_KILLFOCUS, sent }, /* in MDI client */
2861 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2862 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2863 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2864 { WM_SETFOCUS, sent }, /* in MDI client */
2865
2866 { WM_DESTROY, sent },
2867
2868 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2869 { WM_KILLFOCUS, sent },
2870 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2871 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2872 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2873 { WM_SETFOCUS, sent }, /* in MDI client */
2874
2875 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2876 { WM_KILLFOCUS, sent }, /* in MDI client */
2877 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2878 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2879 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2880 { WM_SETFOCUS, sent }, /* in MDI client */
2881
2882 { WM_NCDESTROY, sent },
2883 { 0 }
2884 };
2885 /* CreateWindow for MDI child window, initially invisible */
2886 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2887 { HCBT_CREATEWND, hook },
2888 { WM_NCCREATE, sent },
2889 { WM_NCCALCSIZE, sent|wparam, 0 },
2890 { WM_CREATE, sent },
2891 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2892 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2893 { WM_MOVE, sent },
2894 /* Win2k sends wparam set to
2895 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2896 * while Win9x doesn't bother to set child window id according to
2897 * CLIENTCREATESTRUCT.idFirstChild
2898 */
2899 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2900 { 0 }
2901 };
2902 /* DestroyWindow for MDI child window, initially invisible */
2903 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2904 { HCBT_DESTROYWND, hook },
2905 /* Win2k sends wparam set to
2906 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2907 * while Win9x doesn't bother to set child window id according to
2908 * CLIENTCREATESTRUCT.idFirstChild
2909 */
2910 { 0x0090, sent|optional },
2911 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2912 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2913 { WM_DESTROY, sent },
2914 { WM_NCDESTROY, sent },
2915 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2916 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2917 { 0 }
2918 };
2919 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2920 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2921 { HCBT_CREATEWND, hook },
2922 { WM_NCCREATE, sent },
2923 { WM_NCCALCSIZE, sent|wparam, 0 },
2924 { WM_CREATE, sent },
2925 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2926 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2927 { WM_MOVE, sent },
2928 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2929 { WM_GETMINMAXINFO, sent },
2930 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2931 { WM_NCCALCSIZE, sent|wparam, 1 },
2932 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2933 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2934 /* in MDI frame */
2935 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2936 { WM_NCCALCSIZE, sent|wparam, 1 },
2937 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2938 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2939 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2940 /* Win2k sends wparam set to
2941 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2942 * while Win9x doesn't bother to set child window id according to
2943 * CLIENTCREATESTRUCT.idFirstChild
2944 */
2945 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2946 { WM_SHOWWINDOW, sent|wparam, 1 },
2947 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2948 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2949 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2950 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2951 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2952 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2953 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2954
2955 /* Win9x: message sequence terminates here. */
2956
2957 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2958 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2959 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2960 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2961 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2962 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2963 { HCBT_SETFOCUS, hook|optional },
2964 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2965 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2966 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2967 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2968 { WM_SETFOCUS, sent|defwinproc|optional },
2969 { WM_MDIACTIVATE, sent|defwinproc|optional },
2970 /* in MDI frame */
2971 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2972 { WM_NCCALCSIZE, sent|wparam, 1 },
2973 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2974 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2975 { 0 }
2976 };
2977 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2978 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2979 /* restore the 1st MDI child */
2980 { WM_SETREDRAW, sent|wparam, 0 },
2981 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2982 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2983 { WM_NCCALCSIZE, sent|wparam, 1 },
2984 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2985 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2986 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2987 /* in MDI frame */
2988 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2989 { WM_NCCALCSIZE, sent|wparam, 1 },
2990 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2991 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2992 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2993 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2994 /* create the 2nd MDI child */
2995 { HCBT_CREATEWND, hook },
2996 { WM_NCCREATE, sent },
2997 { WM_NCCALCSIZE, sent|wparam, 0 },
2998 { WM_CREATE, sent },
2999 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3000 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3001 { WM_MOVE, sent },
3002 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3003 { WM_GETMINMAXINFO, sent },
3004 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3005 { WM_NCCALCSIZE, sent|wparam, 1 },
3006 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3007 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3008 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3009 /* in MDI frame */
3010 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3011 { WM_NCCALCSIZE, sent|wparam, 1 },
3012 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3013 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3014 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3015 /* Win2k sends wparam set to
3016 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3017 * while Win9x doesn't bother to set child window id according to
3018 * CLIENTCREATESTRUCT.idFirstChild
3019 */
3020 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3021 { WM_SHOWWINDOW, sent|wparam, 1 },
3022 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3023 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3024 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3025 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3026 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3027 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3028
3029 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3030 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3031
3032 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3033
3034 /* Win9x: message sequence terminates here. */
3035
3036 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3037 { HCBT_SETFOCUS, hook },
3038 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3039 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3040 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3041 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3042 { WM_SETFOCUS, sent }, /* in MDI client */
3043 { HCBT_SETFOCUS, hook },
3044 { WM_KILLFOCUS, sent }, /* in MDI client */
3045 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3046 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3047 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3048 { WM_SETFOCUS, sent|defwinproc },
3049
3050 { WM_MDIACTIVATE, sent|defwinproc },
3051 /* in MDI frame */
3052 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3053 { WM_NCCALCSIZE, sent|wparam, 1 },
3054 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3055 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3056 { 0 }
3057 };
3058 /* WM_MDICREATE MDI child window, initially visible and maximized */
3059 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3060 { WM_MDICREATE, sent },
3061 { HCBT_CREATEWND, hook },
3062 { WM_NCCREATE, sent },
3063 { WM_NCCALCSIZE, sent|wparam, 0 },
3064 { WM_CREATE, sent },
3065 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3066 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3067 { WM_MOVE, sent },
3068 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3069 { WM_GETMINMAXINFO, sent },
3070 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3071 { WM_NCCALCSIZE, sent|wparam, 1 },
3072 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3073 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3074
3075 /* in MDI frame */
3076 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3077 { WM_NCCALCSIZE, sent|wparam, 1 },
3078 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3079 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3080 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3081
3082 /* Win2k sends wparam set to
3083 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3084 * while Win9x doesn't bother to set child window id according to
3085 * CLIENTCREATESTRUCT.idFirstChild
3086 */
3087 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3088 { WM_SHOWWINDOW, sent|wparam, 1 },
3089 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3090
3091 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3092
3093 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3094 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3095 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3096
3097 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3098 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3099
3100 /* Win9x: message sequence terminates here. */
3101
3102 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3103 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3104 { HCBT_SETFOCUS, hook }, /* in MDI client */
3105 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3106 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3107 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3108 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3109 { HCBT_SETFOCUS, hook|optional },
3110 { WM_KILLFOCUS, sent }, /* in MDI client */
3111 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3112 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3113 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3114 { WM_SETFOCUS, sent|defwinproc },
3115
3116 { WM_MDIACTIVATE, sent|defwinproc },
3117
3118 /* in MDI child */
3119 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3120 { WM_NCCALCSIZE, sent|wparam, 1 },
3121 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3122 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3123
3124 /* in MDI frame */
3125 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3126 { WM_NCCALCSIZE, sent|wparam, 1 },
3127 { 0x0093, sent|defwinproc|optional },
3128 { 0x0093, sent|defwinproc|optional },
3129 { 0x0093, sent|defwinproc|optional },
3130 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3131 { WM_MOVE, sent|defwinproc },
3132 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3133
3134 /* in MDI client */
3135 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3136 { WM_NCCALCSIZE, sent|wparam, 1 },
3137 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3138 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3139
3140 /* in MDI child */
3141 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3142 { WM_NCCALCSIZE, sent|wparam, 1 },
3143 { 0x0093, sent|optional },
3144 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3145 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3146
3147 { 0x0093, sent|optional },
3148 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3149 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3150 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3151 { 0x0093, sent|defwinproc|optional },
3152 { 0x0093, sent|defwinproc|optional },
3153 { 0x0093, sent|defwinproc|optional },
3154 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3155 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3156
3157 { 0 }
3158 };
3159 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3160 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3161 { HCBT_CREATEWND, hook },
3162 { WM_GETMINMAXINFO, sent },
3163 { WM_NCCREATE, sent },
3164 { WM_NCCALCSIZE, sent|wparam, 0 },
3165 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3166 { WM_CREATE, sent },
3167 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3168 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3169 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3170 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3171 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3172 { WM_MOVE, sent },
3173 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3174 { WM_GETMINMAXINFO, sent },
3175 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3176 { WM_GETMINMAXINFO, sent|defwinproc },
3177 { WM_NCCALCSIZE, sent|wparam, 1 },
3178 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3179 { WM_MOVE, sent|defwinproc },
3180 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3181 /* in MDI frame */
3182 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3183 { WM_NCCALCSIZE, sent|wparam, 1 },
3184 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3185 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3186 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3187 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3188 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3189 /* Win2k sends wparam set to
3190 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3191 * while Win9x doesn't bother to set child window id according to
3192 * CLIENTCREATESTRUCT.idFirstChild
3193 */
3194 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3195 { 0 }
3196 };
3197 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3198 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3199 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3200 { HCBT_SYSCOMMAND, hook },
3201 { WM_CLOSE, sent|defwinproc },
3202 { WM_MDIDESTROY, sent }, /* in MDI client */
3203
3204 /* bring the 1st MDI child to top */
3205 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3206 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3207
3208 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3209
3210 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3211 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3212 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3213
3214 /* maximize the 1st MDI child */
3215 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3216 { WM_GETMINMAXINFO, sent|defwinproc },
3217 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3218 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3219 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3220 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3221 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3222
3223 /* restore the 2nd MDI child */
3224 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3225 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3226 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3227 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3228
3229 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3230
3231 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3232 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3233
3234 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3235
3236 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3237 /* in MDI frame */
3238 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3239 { WM_NCCALCSIZE, sent|wparam, 1 },
3240 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3241 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3242 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3243
3244 /* bring the 1st MDI child to top */
3245 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3246 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3247 { HCBT_SETFOCUS, hook },
3248 { WM_KILLFOCUS, sent|defwinproc },
3249 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3250 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3251 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3252 { WM_SETFOCUS, sent }, /* in MDI client */
3253 { HCBT_SETFOCUS, hook },
3254 { WM_KILLFOCUS, sent }, /* in MDI client */
3255 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3256 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3257 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3258 { WM_SETFOCUS, sent|defwinproc },
3259 { WM_MDIACTIVATE, sent|defwinproc },
3260 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3261
3262 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3263 { WM_SHOWWINDOW, sent|wparam, 1 },
3264 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3265 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3266 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3267 { WM_MDIREFRESHMENU, sent },
3268
3269 { HCBT_DESTROYWND, hook },
3270 /* Win2k sends wparam set to
3271 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3272 * while Win9x doesn't bother to set child window id according to
3273 * CLIENTCREATESTRUCT.idFirstChild
3274 */
3275 { 0x0090, sent|defwinproc|optional },
3276 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3277 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3278 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3279 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3280 { WM_ERASEBKGND, sent|parent|optional },
3281 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3282
3283 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3284 { WM_DESTROY, sent|defwinproc },
3285 { WM_NCDESTROY, sent|defwinproc },
3286 { 0 }
3287 };
3288 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3289 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3290 { WM_MDIDESTROY, sent }, /* in MDI client */
3291 { WM_SHOWWINDOW, sent|wparam, 0 },
3292 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3293 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3294 { WM_ERASEBKGND, sent|parent|optional },
3295 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3296
3297 { HCBT_SETFOCUS, hook },
3298 { WM_KILLFOCUS, sent },
3299 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3300 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3301 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3302 { WM_SETFOCUS, sent }, /* in MDI client */
3303 { HCBT_SETFOCUS, hook },
3304 { WM_KILLFOCUS, sent }, /* in MDI client */
3305 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3306 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3307 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3308 { WM_SETFOCUS, sent },
3309
3310 /* in MDI child */
3311 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3312 { WM_NCCALCSIZE, sent|wparam, 1 },
3313 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3314 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3315
3316 /* in MDI frame */
3317 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3318 { WM_NCCALCSIZE, sent|wparam, 1 },
3319 { 0x0093, sent|defwinproc|optional },
3320 { 0x0093, sent|defwinproc|optional },
3321 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3322 { WM_MOVE, sent|defwinproc },
3323 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3324
3325 /* in MDI client */
3326 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3327 { WM_NCCALCSIZE, sent|wparam, 1 },
3328 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3329 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3330
3331 /* in MDI child */
3332 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3333 { WM_NCCALCSIZE, sent|wparam, 1 },
3334 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3335 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3336
3337 /* in MDI child */
3338 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3339 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3340 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3341 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3342
3343 /* in MDI frame */
3344 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3345 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3346 { 0x0093, sent|defwinproc|optional },
3347 { 0x0093, sent|defwinproc|optional },
3348 { 0x0093, sent|defwinproc|optional },
3349 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3350 { WM_MOVE, sent|defwinproc },
3351 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3352
3353 /* in MDI client */
3354 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3355 { WM_NCCALCSIZE, sent|wparam, 1 },
3356 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3357 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3358
3359 /* in MDI child */
3360 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3361 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3362 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3363 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3364 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3365 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3366
3367 { 0x0093, sent|defwinproc|optional },
3368 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3369 { 0x0093, sent|defwinproc|optional },
3370 { 0x0093, sent|defwinproc|optional },
3371 { 0x0093, sent|defwinproc|optional },
3372 { 0x0093, sent|optional },
3373
3374 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3375 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3376 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3377 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3378 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3379
3380 /* in MDI frame */
3381 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3382 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3383 { 0x0093, sent|defwinproc|optional },
3384 { 0x0093, sent|defwinproc|optional },
3385 { 0x0093, sent|defwinproc|optional },
3386 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3387 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3388 { 0x0093, sent|optional },
3389
3390 { WM_NCACTIVATE, sent|wparam, 0 },
3391 { WM_MDIACTIVATE, sent },
3392
3393 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3394 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3395 { WM_NCCALCSIZE, sent|wparam, 1 },
3396
3397 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3398
3399 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3400 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3401 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3402
3403 /* in MDI child */
3404 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3405 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3406 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3407 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3408
3409 /* in MDI frame */
3410 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3411 { WM_NCCALCSIZE, sent|wparam, 1 },
3412 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3413 { WM_MOVE, sent|defwinproc },
3414 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3415
3416 /* in MDI client */
3417 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3418 { WM_NCCALCSIZE, sent|wparam, 1 },
3419 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3420 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3421 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3422 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3423 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3424 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3425 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3426
3427 { HCBT_SETFOCUS, hook },
3428 { WM_KILLFOCUS, sent },
3429 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3430 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3431 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3432 { WM_SETFOCUS, sent }, /* in MDI client */
3433
3434 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3435
3436 { HCBT_DESTROYWND, hook },
3437 /* Win2k sends wparam set to
3438 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3439 * while Win9x doesn't bother to set child window id according to
3440 * CLIENTCREATESTRUCT.idFirstChild
3441 */
3442 { 0x0090, sent|optional },
3443 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3444
3445 { WM_SHOWWINDOW, sent|wparam, 0 },
3446 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3447 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3448 { WM_ERASEBKGND, sent|parent|optional },
3449 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3450
3451 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3452 { WM_DESTROY, sent },
3453 { WM_NCDESTROY, sent },
3454 { 0 }
3455 };
3456 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3457 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3458 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3459 { WM_GETMINMAXINFO, sent },
3460 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
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|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3466 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 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|optional|defwinproc },
3477 { WM_MDIACTIVATE, sent|optional|defwinproc },
3478 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3479 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3480 /* in MDI frame */
3481 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3482 { WM_NCCALCSIZE, sent|wparam, 1 },
3483 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3484 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3485 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3486 { 0 }
3487 };
3488 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3489 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3490 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3491 { WM_GETMINMAXINFO, sent },
3492 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3493 { WM_GETMINMAXINFO, sent|defwinproc },
3494 { WM_NCCALCSIZE, sent|wparam, 1 },
3495 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3496 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3497
3498 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3499 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3500 { HCBT_SETFOCUS, hook|optional },
3501 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3502 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3503 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3504 { HCBT_SETFOCUS, hook|optional },
3505 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3506 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3507 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3508 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3509 { WM_SETFOCUS, sent|defwinproc|optional },
3510 { WM_MDIACTIVATE, sent|defwinproc|optional },
3511 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3512 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3513 { 0 }
3514 };
3515 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3516 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3517 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3518 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3519 { WM_GETMINMAXINFO, sent },
3520 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3521 { WM_GETMINMAXINFO, sent|defwinproc },
3522 { WM_NCCALCSIZE, sent|wparam, 1 },
3523 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3524 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3525 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3526 { WM_MOVE, sent|defwinproc },
3527 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3528
3529 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3530 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3531 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3532 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3533 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3534 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3535 /* in MDI frame */
3536 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3537 { WM_NCCALCSIZE, sent|wparam, 1 },
3538 { 0x0093, sent|defwinproc|optional },
3539 { 0x0094, sent|defwinproc|optional },
3540 { 0x0094, sent|defwinproc|optional },
3541 { 0x0094, sent|defwinproc|optional },
3542 { 0x0094, sent|defwinproc|optional },
3543 { 0x0093, sent|defwinproc|optional },
3544 { 0x0093, sent|defwinproc|optional },
3545 { 0x0091, sent|defwinproc|optional },
3546 { 0x0092, sent|defwinproc|optional },
3547 { 0x0092, sent|defwinproc|optional },
3548 { 0x0092, sent|defwinproc|optional },
3549 { 0x0092, sent|defwinproc|optional },
3550 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3551 { WM_MOVE, sent|defwinproc },
3552 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3553 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3554 /* in MDI client */
3555 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3556 { WM_NCCALCSIZE, sent|wparam, 1 },
3557 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3558 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3559 /* in MDI child */
3560 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3561 { WM_GETMINMAXINFO, sent|defwinproc },
3562 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3563 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3564 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3565 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3566 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3567 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3568 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3569 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3570 /* in MDI frame */
3571 { 0x0093, sent|optional },
3572 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3573 { 0x0093, sent|defwinproc|optional },
3574 { 0x0093, sent|defwinproc|optional },
3575 { 0x0093, sent|defwinproc|optional },
3576 { 0x0091, sent|defwinproc|optional },
3577 { 0x0092, sent|defwinproc|optional },
3578 { 0x0092, sent|defwinproc|optional },
3579 { 0x0092, sent|defwinproc|optional },
3580 { 0x0092, sent|defwinproc|optional },
3581 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3582 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3583 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3584 { 0 }
3585 };
3586 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3587 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3588 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3589 { WM_GETMINMAXINFO, sent },
3590 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3591 { WM_NCCALCSIZE, sent|wparam, 1 },
3592 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3593 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3594 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3595 /* in MDI frame */
3596 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3597 { WM_NCCALCSIZE, sent|wparam, 1 },
3598 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3599 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3600 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3601 { 0 }
3602 };
3603 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3604 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3605 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3606 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3607 { WM_NCCALCSIZE, sent|wparam, 1 },
3608 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3609 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3610 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3611 /* in MDI frame */
3612 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3613 { WM_NCCALCSIZE, sent|wparam, 1 },
3614 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3615 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3616 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3617 { 0 }
3618 };
3619 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3620 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3621 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3622 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3623 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3624 { WM_NCCALCSIZE, sent|wparam, 1 },
3625 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3626 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3627 { WM_MOVE, sent|defwinproc },
3628 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3629 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3630 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3631 { HCBT_SETFOCUS, hook },
3632 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3633 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3634 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3635 { WM_SETFOCUS, sent },
3636 { 0 }
3637 };
3638 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3639 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3640 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3641 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3642 { WM_NCCALCSIZE, sent|wparam, 1 },
3643 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3644 { WM_MOVE, sent|defwinproc },
3645 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3646 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3647 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3648 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3649 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3650 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3651 { 0 }
3652 };
3653 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3654 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3655 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3656 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3657 { WM_NCCALCSIZE, sent|wparam, 1 },
3658 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3659 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3660 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3661 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3662 /* in MDI frame */
3663 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3664 { WM_NCCALCSIZE, sent|wparam, 1 },
3665 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3666 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3667 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3668 { 0 }
3669 };
3670
3671 static HWND mdi_client;
3672 static WNDPROC old_mdi_client_proc;
3673
3674 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3675 {
3676 struct recvd_message msg;
3677
3678 /* do not log painting messages */
3679 if (message != WM_PAINT &&
3680 message != WM_NCPAINT &&
3681 message != WM_SYNCPAINT &&
3682 message != WM_ERASEBKGND &&
3683 message != WM_NCHITTEST &&
3684 message != WM_GETTEXT &&
3685 message != WM_MDIGETACTIVE &&
3686 !ignore_message( message ))
3687 {
3688 msg.hwnd = hwnd;
3689 msg.message = message;
3690 msg.flags = sent|wparam|lparam;
3691 msg.wParam = wParam;
3692 msg.lParam = lParam;
3693 msg.descr = "mdi client";
3694 add_message(&msg);
3695 }
3696
3697 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3698 }
3699
3700 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3701 {
3702 static LONG defwndproc_counter = 0;
3703 LRESULT ret;
3704 struct recvd_message msg;
3705
3706 /* do not log painting messages */
3707 if (message != WM_PAINT &&
3708 message != WM_NCPAINT &&
3709 message != WM_SYNCPAINT &&
3710 message != WM_ERASEBKGND &&
3711 message != WM_NCHITTEST &&
3712 message != WM_GETTEXT &&
3713 !ignore_message( message ))
3714 {
3715 switch (message)
3716 {
3717 case WM_MDIACTIVATE:
3718 {
3719 HWND active, client = GetParent(hwnd);
3720
3721 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3722
3723 if (hwnd == (HWND)lParam) /* if we are being activated */
3724 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3725 else
3726 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3727 break;
3728 }
3729 }
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 child";
3738 add_message(&msg);
3739 }
3740
3741 defwndproc_counter++;
3742 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3743 defwndproc_counter--;
3744
3745 return ret;
3746 }
3747
3748 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3749 {
3750 static LONG defwndproc_counter = 0;
3751 LRESULT ret;
3752 struct recvd_message msg;
3753
3754 /* do not log painting messages */
3755 if (message != WM_PAINT &&
3756 message != WM_NCPAINT &&
3757 message != WM_SYNCPAINT &&
3758 message != WM_ERASEBKGND &&
3759 message != WM_NCHITTEST &&
3760 message != WM_GETTEXT &&
3761 !ignore_message( message ))
3762 {
3763 msg.hwnd = hwnd;
3764 msg.message = message;
3765 msg.flags = sent|wparam|lparam;
3766 if (defwndproc_counter) msg.flags |= defwinproc;
3767 msg.wParam = wParam;
3768 msg.lParam = lParam;
3769 msg.descr = "mdi frame";
3770 add_message(&msg);
3771 }
3772
3773 defwndproc_counter++;
3774 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3775 defwndproc_counter--;
3776
3777 return ret;
3778 }
3779
3780 static BOOL mdi_RegisterWindowClasses(void)
3781 {
3782 WNDCLASSA cls;
3783
3784 cls.style = 0;
3785 cls.lpfnWndProc = mdi_frame_wnd_proc;
3786 cls.cbClsExtra = 0;
3787 cls.cbWndExtra = 0;
3788 cls.hInstance = GetModuleHandleA(0);
3789 cls.hIcon = 0;
3790 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3791 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3792 cls.lpszMenuName = NULL;
3793 cls.lpszClassName = "MDI_frame_class";
3794 if (!RegisterClassA(&cls)) return FALSE;
3795
3796 cls.lpfnWndProc = mdi_child_wnd_proc;
3797 cls.lpszClassName = "MDI_child_class";
3798 if (!RegisterClassA(&cls)) return FALSE;
3799
3800 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3801 old_mdi_client_proc = cls.lpfnWndProc;
3802 cls.hInstance = GetModuleHandleA(0);
3803 cls.lpfnWndProc = mdi_client_hook_proc;
3804 cls.lpszClassName = "MDI_client_class";
3805 if (!RegisterClassA(&cls)) assert(0);
3806
3807 return TRUE;
3808 }
3809
3810 static void test_mdi_messages(void)
3811 {
3812 MDICREATESTRUCTA mdi_cs;
3813 CLIENTCREATESTRUCT client_cs;
3814 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3815 BOOL zoomed;
3816 RECT rc;
3817 HMENU hMenu = CreateMenu();
3818 LONG val;
3819
3820 if (!mdi_RegisterWindowClasses()) assert(0);
3821
3822 flush_sequence();
3823
3824 trace("creating MDI frame window\n");
3825 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3826 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3827 WS_MAXIMIZEBOX | WS_VISIBLE,
3828 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3829 GetDesktopWindow(), hMenu,
3830 GetModuleHandleA(0), NULL);
3831 assert(mdi_frame);
3832 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3833
3834 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3835 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3836
3837 trace("creating MDI client window\n");
3838 GetClientRect(mdi_frame, &rc);
3839 client_cs.hWindowMenu = 0;
3840 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3841 mdi_client = CreateWindowExA(0, "MDI_client_class",
3842 NULL,
3843 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3844 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3845 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3846 assert(mdi_client);
3847 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3848
3849 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3850 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3851 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3852
3853 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3854 ok(!active_child, "wrong active MDI child %p\n", active_child);
3855 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3856
3857 SetFocus(0);
3858 flush_sequence();
3859
3860 trace("creating invisible MDI child window\n");
3861 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3862 WS_CHILD,
3863 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3864 mdi_client, 0, GetModuleHandleA(0), NULL);
3865 assert(mdi_child);
3866
3867 flush_sequence();
3868 ShowWindow(mdi_child, SW_SHOWNORMAL);
3869 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3870
3871 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3872 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3873
3874 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3875 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3876
3877 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3878 ok(!active_child, "wrong active MDI child %p\n", active_child);
3879 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3880
3881 ShowWindow(mdi_child, SW_HIDE);
3882 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3883 flush_sequence();
3884
3885 ShowWindow(mdi_child, SW_SHOW);
3886 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3887
3888 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3889 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3890
3891 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3892 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3893
3894 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3895 ok(!active_child, "wrong active MDI child %p\n", active_child);
3896 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3897
3898 DestroyWindow(mdi_child);
3899 flush_sequence();
3900
3901 trace("creating visible MDI child window\n");
3902 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3903 WS_CHILD | WS_VISIBLE,
3904 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3905 mdi_client, 0, GetModuleHandleA(0), NULL);
3906 assert(mdi_child);
3907 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3908
3909 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3910 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3911
3912 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3913 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3914
3915 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3916 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3917 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3918 flush_sequence();
3919
3920 DestroyWindow(mdi_child);
3921 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3922
3923 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3924 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3925
3926 /* Win2k: MDI client still returns a just destroyed child as active
3927 * Win9x: MDI client returns 0
3928 */
3929 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3930 ok(active_child == mdi_child || /* win2k */
3931 !active_child, /* win9x */
3932 "wrong active MDI child %p\n", active_child);
3933 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3934
3935 flush_sequence();
3936
3937 trace("creating invisible MDI child window\n");
3938 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3939 WS_CHILD,
3940 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3941 mdi_client, 0, GetModuleHandleA(0), NULL);
3942 assert(mdi_child2);
3943 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3944
3945 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3946 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3947
3948 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3949 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3950
3951 /* Win2k: MDI client still returns a just destroyed child as active
3952 * Win9x: MDI client returns mdi_child2
3953 */
3954 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3955 ok(active_child == mdi_child || /* win2k */
3956 active_child == mdi_child2, /* win9x */
3957 "wrong active MDI child %p\n", active_child);
3958 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3959 flush_sequence();
3960
3961 ShowWindow(mdi_child2, SW_MAXIMIZE);
3962 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3963
3964 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3965 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3966
3967 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3968 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3969 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3970 flush_sequence();
3971
3972 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3973 ok(GetFocus() == mdi_child2 || /* win2k */
3974 GetFocus() == 0, /* win9x */
3975 "wrong focus window %p\n", GetFocus());
3976
3977 SetFocus(0);
3978 flush_sequence();
3979
3980 ShowWindow(mdi_child2, SW_HIDE);
3981 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3982
3983 ShowWindow(mdi_child2, SW_RESTORE);
3984 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3985 flush_sequence();
3986
3987 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3988 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3989
3990 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3991 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3992 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3993 flush_sequence();
3994
3995 SetFocus(0);
3996 flush_sequence();
3997
3998 ShowWindow(mdi_child2, SW_HIDE);
3999 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4000
4001 ShowWindow(mdi_child2, SW_SHOW);
4002 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
4003
4004 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4005 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4006
4007 ShowWindow(mdi_child2, SW_MAXIMIZE);
4008 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
4009
4010 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4011 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4012
4013 ShowWindow(mdi_child2, SW_RESTORE);
4014 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4015
4016 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4017 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4018
4019 ShowWindow(mdi_child2, SW_MINIMIZE);
4020 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
4021
4022 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4023 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4024
4025 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4026 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4027 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4028 flush_sequence();
4029
4030 ShowWindow(mdi_child2, SW_RESTORE);
4031 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4032
4033 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4034 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
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 flush_sequence();
4040
4041 SetFocus(0);
4042 flush_sequence();
4043
4044 ShowWindow(mdi_child2, SW_HIDE);
4045 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4046
4047 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4048 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4049
4050 DestroyWindow(mdi_child2);
4051 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4052
4053 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4054 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4055
4056 trace("Testing WM_CHILDACTIVATE\n");
4057
4058 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4059 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4060 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4061 mdi_client, 0, GetModuleHandleA(0), NULL);
4062
4063 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4064 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4065 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4066 mdi_client, 0, GetModuleHandleA(0), NULL);
4067
4068 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4069 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4070 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4071
4072 flush_sequence();
4073 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4074 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4075
4076 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4077 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4078 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4079 flush_sequence();
4080
4081 EnableWindow(mdi_child, TRUE);
4082
4083 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4084 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4085 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4086
4087 flush_sequence();
4088 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4089 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4090
4091 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4092 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4093 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4094 flush_sequence();
4095
4096 DestroyWindow(mdi_child);
4097 DestroyWindow(mdi_child2);
4098 flush_sequence();
4099
4100 /* test for maximized MDI children */
4101 trace("creating maximized visible MDI child window 1\n");
4102 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4103 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4104 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4105 mdi_client, 0, GetModuleHandleA(0), NULL);
4106 assert(mdi_child);
4107 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4108 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4109
4110 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4111 ok(GetFocus() == mdi_child || /* win2k */
4112 GetFocus() == 0, /* win9x */
4113 "wrong focus window %p\n", GetFocus());
4114
4115 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4116 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4117 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4118 flush_sequence();
4119
4120 trace("creating maximized visible MDI child window 2\n");
4121 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4122 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4123 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4124 mdi_client, 0, GetModuleHandleA(0), NULL);
4125 assert(mdi_child2);
4126 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4127 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4128 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4129
4130 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4131 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4132
4133 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4134 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4135 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4136 flush_sequence();
4137
4138 trace("destroying maximized visible MDI child window 2\n");
4139 DestroyWindow(mdi_child2);
4140 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4141
4142 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4143
4144 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4145 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4146
4147 /* Win2k: MDI client still returns a just destroyed child as active
4148 * Win9x: MDI client returns 0
4149 */
4150 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4151 ok(active_child == mdi_child2 || /* win2k */
4152 !active_child, /* win9x */
4153 "wrong active MDI child %p\n", active_child);
4154 flush_sequence();
4155
4156 ShowWindow(mdi_child, SW_MAXIMIZE);
4157 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4158 flush_sequence();
4159
4160 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4161 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4162
4163 trace("re-creating maximized visible MDI child window 2\n");
4164 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4165 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4166 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4167 mdi_client, 0, GetModuleHandleA(0), NULL);
4168 assert(mdi_child2);
4169 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4170 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4171 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4172
4173 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4174 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4175
4176 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4177 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4178 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4179 flush_sequence();
4180
4181 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4182 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4183 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4184
4185 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4186 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4187 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4188
4189 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4190 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4191 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4192 flush_sequence();
4193
4194 DestroyWindow(mdi_child);
4195 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4196
4197 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4198 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4199
4200 /* Win2k: MDI client still returns a just destroyed child as active
4201 * Win9x: MDI client returns 0
4202 */
4203 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4204 ok(active_child == mdi_child || /* win2k */
4205 !active_child, /* win9x */
4206 "wrong active MDI child %p\n", active_child);
4207 flush_sequence();
4208
4209 trace("creating maximized invisible MDI child window\n");
4210 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4211 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4212 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4213 mdi_client, 0, GetModuleHandleA(0), NULL);
4214 assert(mdi_child2);
4215 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4216 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4217 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4218 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4219
4220 /* Win2k: MDI client still returns a just destroyed child as active
4221 * Win9x: MDI client returns 0
4222 */
4223 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4224 ok(active_child == mdi_child || /* win2k */
4225 !active_child || active_child == mdi_child2, /* win9x */
4226 "wrong active MDI child %p\n", active_child);
4227 flush_sequence();
4228
4229 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4230 ShowWindow(mdi_child2, SW_MAXIMIZE);
4231 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4232 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4233 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4234 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4235
4236 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4237 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4238 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4239 flush_sequence();
4240
4241 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4242 flush_sequence();
4243
4244 /* end of test for maximized MDI children */
4245 SetFocus(0);
4246 flush_sequence();
4247 trace("creating maximized visible MDI child window 1(Switch test)\n");
4248 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4249 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4250 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4251 mdi_client, 0, GetModuleHandleA(0), NULL);
4252 assert(mdi_child);
4253 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4254 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4255
4256 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4257 ok(GetFocus() == mdi_child || /* win2k */
4258 GetFocus() == 0, /* win9x */
4259 "wrong focus window %p(Switch test)\n", GetFocus());
4260
4261 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4262 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4263 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4264 flush_sequence();
4265
4266 trace("creating maximized visible MDI child window 2(Switch test)\n");
4267 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4268 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4269 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4270 mdi_client, 0, GetModuleHandleA(0), NULL);
4271 assert(mdi_child2);
4272 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4273
4274 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4275 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4276
4277 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4278 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4279
4280 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4281 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4282 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4283 flush_sequence();
4284
4285 trace("Switch child window.\n");
4286 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4287 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4288 trace("end of test for switch maximized MDI children\n");
4289 flush_sequence();
4290
4291 /* Prepare for switching test of not maximized MDI children */
4292 ShowWindow( mdi_child, SW_NORMAL );
4293 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4294 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4295 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4296 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4297 flush_sequence();
4298
4299 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4300 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4301 trace("end of test for switch not maximized MDI children\n");
4302 flush_sequence();
4303
4304 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4305 flush_sequence();
4306
4307 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4308 flush_sequence();
4309
4310 SetFocus(0);
4311 flush_sequence();
4312 /* end of tests for switch maximized/not maximized MDI children */
4313
4314 mdi_cs.szClass = "MDI_child_Class";
4315 mdi_cs.szTitle = "MDI child";
4316 mdi_cs.hOwner = GetModuleHandleA(0);
4317 mdi_cs.x = 0;
4318 mdi_cs.y = 0;
4319 mdi_cs.cx = CW_USEDEFAULT;
4320 mdi_cs.cy = CW_USEDEFAULT;
4321 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4322 mdi_cs.lParam = 0;
4323 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4324 ok(mdi_child != 0, "MDI child creation failed\n");
4325 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4326
4327 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4328
4329 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4330 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4331
4332 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4333 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4334 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4335
4336 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4337 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4338 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4339 flush_sequence();
4340
4341 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4342 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4343
4344 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4345 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4346 ok(!active_child, "wrong active MDI child %p\n", active_child);
4347
4348 SetFocus(0);
4349 flush_sequence();
4350
4351 val = GetWindowLongA(mdi_client, 0);
4352 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4353 DestroyWindow(mdi_client);
4354 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4355
4356 /* test maximization of MDI child with invisible parent */
4357 client_cs.hWindowMenu = 0;
4358 mdi_client = CreateWindowA("MDI_client_class",
4359 NULL,
4360 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4361 0, 0, 660, 430,
4362 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4363 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4364
4365 ShowWindow(mdi_client, SW_HIDE);
4366 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4367
4368 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4369 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4370 0, 0, 650, 440,
4371 mdi_client, 0, GetModuleHandleA(0), NULL);
4372 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4373
4374 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4375 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4376 zoomed = IsZoomed(mdi_child);
4377 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4378
4379 ShowWindow(mdi_client, SW_SHOW);
4380 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4381
4382 DestroyWindow(mdi_child);
4383 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4384
4385 /* end of test for maximization of MDI child with invisible parent */
4386
4387 DestroyWindow(mdi_client);
4388 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4389
4390 DestroyWindow(mdi_frame);
4391 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4392 }
4393 /************************* End of MDI test **********************************/
4394
4395 static void test_WM_SETREDRAW(HWND hwnd)
4396 {
4397 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4398
4399 flush_events();
4400 flush_sequence();
4401
4402 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4403 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4404
4405 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4406 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4407
4408 flush_sequence();
4409 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4410 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4411
4412 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4413 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4414
4415 /* restore original WS_VISIBLE state */
4416 SetWindowLongA(hwnd, GWL_STYLE, style);
4417
4418 flush_events();
4419 flush_sequence();
4420 }
4421
4422 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4423 {
4424 struct recvd_message msg;
4425
4426 if (ignore_message( message )) return 0;
4427
4428 switch (message)
4429 {
4430 /* ignore */
4431 case WM_MOUSEMOVE:
4432 case WM_NCMOUSEMOVE:
4433 case WM_NCMOUSELEAVE:
4434 case WM_SETCURSOR:
4435 return 0;
4436 case WM_NCHITTEST:
4437 return HTCLIENT;
4438 }
4439
4440 msg.hwnd = hwnd;
4441 msg.message = message;
4442 msg.flags = sent|wparam|lparam;
4443 msg.wParam = wParam;
4444 msg.lParam = lParam;
4445 msg.descr = "dialog";
4446 add_message(&msg);
4447
4448 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4449 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4450 return 0;
4451 }
4452
4453 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4454 {
4455 struct recvd_message msg;
4456
4457 if (ignore_message( message )) return 0;
4458
4459 switch (message)
4460 {
4461 /* ignore */
4462 case WM_MOUSEMOVE:
4463 case WM_NCMOUSEMOVE:
4464 case WM_NCMOUSELEAVE:
4465 case WM_SETCURSOR:
4466 return 0;
4467 case WM_NCHITTEST:
4468 return HTCLIENT;
4469 }
4470
4471 msg.hwnd = hwnd;
4472 msg.message = message;
4473 msg.flags = sent|wparam|lparam;
4474 msg.wParam = wParam;
4475 msg.lParam = lParam;
4476 msg.descr = "dialog";
4477 add_message(&msg);
4478
4479 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4480 return 0;
4481 }
4482
4483 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4484 {
4485 DWORD style, exstyle;
4486 INT xmin, xmax;
4487 BOOL ret;
4488
4489 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4490 style = GetWindowLongA(hwnd, GWL_STYLE);
4491 /* do not be confused by WS_DLGFRAME set */
4492 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4493
4494 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4495 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4496
4497 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4498 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4499 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4500 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4501 else
4502 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4503
4504 style = GetWindowLongA(hwnd, GWL_STYLE);
4505 if (set) ok(style & set, "style %08x should be set\n", set);
4506 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4507
4508 /* a subsequent call should do nothing */
4509 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4510 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4511 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4512
4513 xmin = 0xdeadbeef;
4514 xmax = 0xdeadbeef;
4515 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4516 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4517 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4518 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4519 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4520 }
4521
4522 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4523 {
4524 DWORD style, exstyle;
4525 SCROLLINFO si;
4526 BOOL ret;
4527
4528 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4529 style = GetWindowLongA(hwnd, GWL_STYLE);
4530 /* do not be confused by WS_DLGFRAME set */
4531 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4532
4533 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4534 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4535
4536 si.cbSize = sizeof(si);
4537 si.fMask = SIF_RANGE;
4538 si.nMin = min;
4539 si.nMax = max;
4540 SetScrollInfo(hwnd, ctl, &si, TRUE);
4541 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4542 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4543 else
4544 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4545
4546 style = GetWindowLongA(hwnd, GWL_STYLE);
4547 if (set) ok(style & set, "style %08x should be set\n", set);
4548 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4549
4550 /* a subsequent call should do nothing */
4551 SetScrollInfo(hwnd, ctl, &si, TRUE);
4552 if (style & WS_HSCROLL)
4553 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4554 else if (style & WS_VSCROLL)
4555 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4556 else
4557 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4558
4559 si.fMask = SIF_PAGE;
4560 si.nPage = 5;
4561 SetScrollInfo(hwnd, ctl, &si, FALSE);
4562 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4563
4564 si.fMask = SIF_POS;
4565 si.nPos = max - 1;
4566 SetScrollInfo(hwnd, ctl, &si, FALSE);
4567 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4568
4569 si.fMask = SIF_RANGE;
4570 si.nMin = 0xdeadbeef;
4571 si.nMax = 0xdeadbeef;
4572 ret = GetScrollInfo(hwnd, ctl, &si);
4573 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4574 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4575 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4576 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4577 }
4578
4579 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4580 static void test_scroll_messages(HWND hwnd)
4581 {
4582 SCROLLINFO si;
4583 INT min, max;
4584 BOOL ret;
4585
4586 flush_events();
4587 flush_sequence();
4588
4589 min = 0xdeadbeef;
4590 max = 0xdeadbeef;
4591 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4592 ok( ret, "GetScrollRange error %d\n", GetLastError());
4593 if (sequence->message != WmGetScrollRangeSeq[0].message)
4594 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4595 /* values of min and max are undefined */
4596 flush_sequence();
4597
4598 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4599 ok( ret, "SetScrollRange error %d\n", GetLastError());
4600 if (sequence->message != WmSetScrollRangeSeq[0].message)
4601 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4602 flush_sequence();
4603
4604 min = 0xdeadbeef;
4605 max = 0xdeadbeef;
4606 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4607 ok( ret, "GetScrollRange error %d\n", GetLastError());
4608 if (sequence->message != WmGetScrollRangeSeq[0].message)
4609 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4610 /* values of min and max are undefined */
4611 flush_sequence();
4612
4613 si.cbSize = sizeof(si);
4614 si.fMask = SIF_RANGE;
4615 si.nMin = 20;
4616 si.nMax = 160;
4617 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4618 if (sequence->message != WmSetScrollRangeSeq[0].message)
4619 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4620 flush_sequence();
4621
4622 si.fMask = SIF_PAGE;
4623 si.nPage = 10;
4624 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4625 if (sequence->message != WmSetScrollRangeSeq[0].message)
4626 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4627 flush_sequence();
4628
4629 si.fMask = SIF_POS;
4630 si.nPos = 20;
4631 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4632 if (sequence->message != WmSetScrollRangeSeq[0].message)
4633 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4634 flush_sequence();
4635
4636 si.fMask = SIF_RANGE;
4637 si.nMin = 0xdeadbeef;
4638 si.nMax = 0xdeadbeef;
4639 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4640 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4641 if (sequence->message != WmGetScrollInfoSeq[0].message)
4642 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4643 /* values of min and max are undefined */
4644 flush_sequence();
4645
4646 /* set WS_HSCROLL */
4647 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4648 /* clear WS_HSCROLL */
4649 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4650
4651 /* set WS_HSCROLL */
4652 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4653 /* clear WS_HSCROLL */
4654 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4655
4656 /* set WS_VSCROLL */
4657 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4658 /* clear WS_VSCROLL */
4659 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4660
4661 /* set WS_VSCROLL */
4662 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4663 /* clear WS_VSCROLL */
4664 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4665 }
4666
4667 static void test_showwindow(void)
4668 {
4669 HWND hwnd, hchild;
4670 RECT rc;
4671
4672 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4673 100, 100, 200, 200, 0, 0, 0, NULL);
4674 ok (hwnd != 0, "Failed to create overlapped window\n");
4675 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4676 0, 0, 10, 10, hwnd, 0, 0, NULL);
4677 ok (hchild != 0, "Failed to create child\n");
4678 flush_sequence();
4679
4680 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4681 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4682 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4683 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4684
4685 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4686 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4687 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4688 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4689 /* back to invisible */
4690 ShowWindow(hchild, SW_HIDE);
4691 ShowWindow(hwnd, SW_HIDE);
4692 flush_sequence();
4693 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4694 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4695 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4696 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4697 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4698 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4699 flush_sequence();
4700 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4701 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4702 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4703 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4704 ShowWindow( hwnd, SW_SHOW);
4705 flush_sequence();
4706 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4707 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4708 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4709
4710 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4711 ShowWindow( hchild, SW_HIDE);
4712 flush_sequence();
4713 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4714 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4715 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4716
4717 SetCapture(hchild);
4718 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4719 DestroyWindow(hchild);
4720 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4721
4722 DestroyWindow(hwnd);
4723 flush_sequence();
4724
4725 /* Popup windows */
4726 /* Test 1:
4727 * 1. Create invisible maximized popup window.
4728 * 2. Move and resize it.
4729 * 3. 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 GetWindowRect(hwnd, &rc);
4739 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4740 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4741 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4742 /* Reset window's size & position */
4743 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4744 ok(IsZoomed(hwnd), "window should be maximized\n");
4745 flush_sequence();
4746
4747 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4748 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4749 ok(IsZoomed(hwnd), "window should be maximized\n");
4750 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4751
4752 GetWindowRect(hwnd, &rc);
4753 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4754 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4755 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4756 DestroyWindow(hwnd);
4757 flush_sequence();
4758
4759 /* Test again, this time the NC_PAINT message */
4760 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4761 100, 100, 200, 200, 0, 0, 0, NULL);
4762 ok (hwnd != 0, "Failed to create popup window\n");
4763 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4764 flush_sequence();
4765 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4766 ok_sequence(WmShowMaxPopupResizedSeq_todo,
4767 "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", TRUE);
4768 DestroyWindow(hwnd);
4769 flush_sequence();
4770
4771 /* Test 2:
4772 * 1. Create invisible maximized popup window.
4773 * 2. Show it maximized.
4774 */
4775 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4776 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4777 100, 100, 200, 200, 0, 0, 0, NULL);
4778 ok (hwnd != 0, "Failed to create popup window\n");
4779 ok(IsZoomed(hwnd), "window should be maximized\n");
4780 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4781
4782 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4783 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4784 ok(IsZoomed(hwnd), "window should be maximized\n");
4785 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4786 DestroyWindow(hwnd);
4787 flush_sequence();
4788
4789 /* Test 3:
4790 * 1. Create visible maximized popup window.
4791 */
4792 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4793 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4794 100, 100, 200, 200, 0, 0, 0, NULL);
4795 ok (hwnd != 0, "Failed to create popup window\n");
4796 ok(IsZoomed(hwnd), "window should be maximized\n");
4797 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4798 DestroyWindow(hwnd);
4799 flush_sequence();
4800
4801 /* Test 4:
4802 * 1. Create visible popup window.
4803 * 2. Maximize it.
4804 */
4805 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4806 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4807 100, 100, 200, 200, 0, 0, 0, NULL);
4808 ok (hwnd != 0, "Failed to create popup window\n");
4809 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4810 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4811
4812 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4813 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4814 ok(IsZoomed(hwnd), "window should be maximized\n");
4815 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4816 DestroyWindow(hwnd);
4817 flush_sequence();
4818 }
4819
4820 static void test_sys_menu(void)
4821 {
4822 HWND hwnd;
4823 HMENU hmenu;
4824 UINT state;
4825
4826 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4827 100, 100, 200, 200, 0, 0, 0, NULL);
4828 ok (hwnd != 0, "Failed to create overlapped window\n");
4829
4830 flush_sequence();
4831
4832 /* test existing window without CS_NOCLOSE style */
4833 hmenu = GetSystemMenu(hwnd, FALSE);
4834 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4835
4836 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4837 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4838 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4839
4840 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4841 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4842
4843 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4844 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4845 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4846
4847 EnableMenuItem(hmenu, SC_CLOSE, 0);
4848 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4849
4850 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4851 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4852 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4853
4854 /* test whether removing WS_SYSMENU destroys a system menu */
4855 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4856 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4857 flush_sequence();
4858 hmenu = GetSystemMenu(hwnd, FALSE);
4859 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4860
4861 DestroyWindow(hwnd);
4862
4863 /* test new window with CS_NOCLOSE style */
4864 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4865 100, 100, 200, 200, 0, 0, 0, NULL);
4866 ok (hwnd != 0, "Failed to create overlapped window\n");
4867
4868 hmenu = GetSystemMenu(hwnd, FALSE);
4869 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4870
4871 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4872 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4873
4874 DestroyWindow(hwnd);
4875
4876 /* test new window without WS_SYSMENU style */
4877 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4878 100, 100, 200, 200, 0, 0, 0, NULL);
4879 ok(hwnd != 0, "Failed to create overlapped window\n");
4880
4881 hmenu = GetSystemMenu(hwnd, FALSE);
4882 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4883
4884 DestroyWindow(hwnd);
4885 }
4886
4887 /* For shown WS_OVERLAPPEDWINDOW */
4888 static const struct message WmSetIcon_1[] = {
4889 { WM_SETICON, sent },
4890 { 0x00AE, sent|defwinproc|optional }, /* XP */
4891 { WM_GETTEXT, sent|defwinproc|optional },
4892 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4893 { 0 }
4894 };
4895
4896 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4897 static const struct message WmSetIcon_2[] = {
4898 { WM_SETICON, sent },
4899 { 0 }
4900 };
4901
4902 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4903 static const struct message WmInitEndSession[] = {
4904 { 0x003B, sent },
4905 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4906 { 0 }
4907 };
4908
4909 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4910 static const struct message WmInitEndSession_2[] = {
4911 { 0x003B, sent },
4912 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4913 { 0 }
4914 };
4915
4916 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4917 static const struct message WmInitEndSession_3[] = {
4918 { 0x003B, sent },
4919 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4920 { 0 }
4921 };
4922
4923 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4924 static const struct message WmInitEndSession_4[] = {
4925 { 0x003B, sent },
4926 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4927 { 0 }
4928 };
4929
4930 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4931 static const struct message WmInitEndSession_5[] = {
4932 { 0x003B, sent },
4933 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4934 { 0 }
4935 };
4936
4937 static const struct message WmOptionalPaint[] = {
4938 { WM_PAINT, sent|optional },
4939 { WM_NCPAINT, sent|beginpaint|optional },
4940 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4941 { WM_ERASEBKGND, sent|beginpaint|optional },
4942 { 0 }
4943 };
4944
4945 static const struct message WmZOrder[] = {
4946 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4947 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4948 { HCBT_ACTIVATE, hook },
4949 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4950 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4951 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4952 { WM_GETTEXT, sent|optional },
4953 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4954 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4955 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4956 { WM_GETTEXT, sent|defwinproc|optional },
4957 { WM_GETTEXT, sent|defwinproc|optional },
4958 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4959 { HCBT_SETFOCUS, hook },
4960 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4961 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4962 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4963 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4964 { WM_GETTEXT, sent|optional },
4965 { WM_NCCALCSIZE, sent|optional },
4966 { 0 }
4967 };
4968
4969 static void CALLBACK apc_test_proc(ULONG_PTR param)
4970 {
4971 /* nothing */
4972 }
4973
4974 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4975 {
4976 DWORD ret;
4977 MSG msg;
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_REMOVE ), "PeekMessage should succeed\n");
4988 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4989
4990 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4991 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4992
4993 PostMessageA(hwnd, WM_USER, 0, 0);
4994
4995 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4996 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4997
4998 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4999 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5000
5001 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
5002 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5003 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
5004
5005 PostMessageA(hwnd, WM_USER, 0, 0);
5006
5007 /* new incoming message causes it to become signaled again */
5008 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5009 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5010
5011 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5012 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
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 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5017 PostMessageA( hwnd, WM_USER, 0, 0 );
5018 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5019 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5020
5021 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5022 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5023
5024 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5025 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5026
5027 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5028 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5029 ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5030
5031 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5032 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5033
5034 /* but even with MWMO_ALERTABLE window events are preferred */
5035 PostMessageA( hwnd, WM_USER, 0, 0 );
5036
5037 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5038 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5039
5040 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5041 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5042
5043 /* the APC call is still queued */
5044 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5045 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5046 }
5047
5048 static void test_WM_DEVICECHANGE(HWND hwnd)
5049 {
5050 DWORD ret;
5051 MSG msg;
5052 int i;
5053 static const WPARAM wparams[] = {0,
5054 DBT_DEVNODES_CHANGED,
5055 DBT_QUERYCHANGECONFIG,
5056 DBT_CONFIGCHANGED,
5057 DBT_CONFIGCHANGECANCELED,
5058 DBT_NO_DISK_SPACE,
5059 DBT_LOW_DISK_SPACE,
5060 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5061 DBT_DEVICEARRIVAL, /* 0x8000 */
5062 DBT_DEVICEQUERYREMOVE,
5063 DBT_DEVICEQUERYREMOVEFAILED,
5064 DBT_DEVICEREMOVEPENDING,
5065 DBT_DEVICEREMOVECOMPLETE,
5066 DBT_DEVICETYPESPECIFIC,
5067 DBT_CUSTOMEVENT};
5068
5069 for (i = 0; i < sizeof(wparams)/sizeof(wparams[0]); i++)
5070 {
5071 SetLastError(0xdeadbeef);
5072 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5073 if (wparams[i] & 0x8000)
5074 {
5075 ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5076 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5077 }
5078 else
5079 {
5080 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5081 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5082 memset(&msg, 0, sizeof(msg));
5083 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5084 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5085 }
5086 }
5087 }
5088
5089 static DWORD CALLBACK show_window_thread(LPVOID arg)
5090 {
5091 HWND hwnd = arg;
5092
5093 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5094 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5095
5096 return 0;
5097 }
5098
5099 /* Helper function to easier test SetWindowPos messages */
5100 #define test_msg_setpos( expected_list, flags, todo ) \
5101 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5102 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5103 {
5104 HWND hwnd;
5105
5106 flush_events();
5107 flush_sequence();
5108 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5109 10, 10, 100, 100, NULL, 0, 0, NULL );
5110 ok (hwnd != 0, "Failed to create popup window\n");
5111 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5112 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5113 DestroyWindow(hwnd);
5114 }
5115
5116 /* test if we receive the right sequence of messages */
5117 static void test_messages(void)
5118 {
5119 DWORD tid;
5120 HANDLE hthread;
5121 HWND hwnd, hparent, hchild;
5122 HWND hchild2, hbutton;
5123 HMENU hmenu;
5124 MSG msg;
5125 LRESULT res;
5126 POINT pos;
5127 BOOL ret;
5128
5129 flush_sequence();
5130
5131 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5132 100, 100, 200, 200, 0, 0, 0, NULL);
5133 ok (hwnd != 0, "Failed to create overlapped window\n");
5134 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5135
5136 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5137 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5138 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5139
5140 /* test WM_SETREDRAW on a not visible top level window */
5141 test_WM_SETREDRAW(hwnd);
5142
5143 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5144 flush_events();
5145 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5146 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5147
5148 ok(GetActiveWindow() == hwnd, "window should be active\n");
5149 ok(GetFocus() == hwnd, "window should have input focus\n");
5150 ShowWindow(hwnd, SW_HIDE);
5151 flush_events();
5152 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5153
5154 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5155 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5156 flush_events();
5157 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5158
5159 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5160 hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5161 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5162 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5163 CloseHandle(hthread);
5164 flush_events();
5165 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5166
5167 ShowWindow(hwnd, SW_SHOW);
5168 flush_events();
5169 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5170
5171 ShowWindow(hwnd, SW_HIDE);
5172 flush_events();
5173 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5174
5175 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5176 flush_events();
5177 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5178 flush_sequence();
5179
5180 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5181 {
5182 ShowWindow(hwnd, SW_RESTORE);
5183 flush_events();
5184 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5185 flush_sequence();
5186 }
5187
5188 ShowWindow(hwnd, SW_MINIMIZE);
5189 flush_events();
5190 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5191 flush_sequence();
5192
5193 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5194 {
5195 ShowWindow(hwnd, SW_RESTORE);
5196 flush_events();
5197 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5198 flush_sequence();
5199 }
5200
5201 ShowWindow(hwnd, SW_SHOW);
5202 flush_events();
5203 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5204
5205 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5206 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5207 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5208 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5209
5210 /* test WM_SETREDRAW on a visible top level window */
5211 ShowWindow(hwnd, SW_SHOW);
5212 flush_events();
5213 test_WM_SETREDRAW(hwnd);
5214
5215 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5216 test_scroll_messages(hwnd);
5217
5218 /* test resizing and moving */
5219 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5220 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5221 flush_events();
5222 flush_sequence();
5223 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5224 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5225 flush_events();
5226 flush_sequence();
5227 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5228 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5229 flush_events();
5230 flush_sequence();
5231
5232 /* popups don't get WM_GETMINMAXINFO */
5233 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5234 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5235 flush_sequence();
5236 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5237 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5238
5239 DestroyWindow(hwnd);
5240 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5241
5242 /* Test if windows are correctly drawn when first shown */
5243
5244 /* Visible, redraw */
5245 flush_events();
5246 flush_sequence();
5247 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5248 10, 10, 100, 100, NULL, 0, 0, NULL );
5249 ok (hwnd != 0, "Failed to create popup window\n");
5250 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5251 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5252 DestroyWindow(hwnd);
5253
5254 /* Invisible, show, message */
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_SHOW);
5261 SendMessageW(hwnd, WM_PAINT, 0, 0);
5262 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5263 DestroyWindow(hwnd);
5264
5265 /* Invisible, show maximized, redraw */
5266 flush_events();
5267 flush_sequence();
5268 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5269 10, 10, 100, 100, NULL, 0, 0, NULL );
5270 ok (hwnd != 0, "Failed to create popup window\n");
5271 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5272 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5273 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5274 DestroyWindow(hwnd);
5275
5276 /* Test SetWindowPos */
5277 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5278 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5279 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5280 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5281
5282 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5283 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5284 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5285 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5286 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5287
5288 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5289 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5290 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5291 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5292 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5293 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5294
5295 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5296 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5297 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5298 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5299 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5300 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5301
5302 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5303 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5304 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5305 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5306 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5307 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5308
5309 /* Test SetWindowPos with child windows */
5310 flush_events();
5311 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5312 100, 100, 200, 200, 0, 0, 0, NULL);
5313 ok (hparent != 0, "Failed to create parent window\n");
5314
5315 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5316 0, 0, 10, 10, hparent, 0, 0, NULL);
5317 ok (hchild != 0, "Failed to create child window\n");
5318 flush_sequence();
5319 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5320 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5321 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5322 DestroyWindow(hchild);
5323 DestroyWindow(hparent);
5324
5325 flush_events();
5326 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5327 100, 100, 200, 200, 0, 0, 0, NULL);
5328 ok (hparent != 0, "Failed to create parent window\n");
5329
5330 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5331 0, 0, 10, 10, hparent, 0, 0, NULL);
5332 ok (hchild != 0, "Failed to create child window\n");
5333 flush_sequence();
5334 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5335 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5336 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5337 DestroyWindow(hchild);
5338 DestroyWindow(hparent);
5339
5340 /* Test message sequence for extreme position and size */
5341
5342 flush_sequence();
5343 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5344 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5345 ok (hwnd != 0, "Failed to create popup window\n");
5346 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE);
5347 DestroyWindow(hwnd);
5348
5349
5350 /* Test child windows */
5351
5352 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5353 100, 100, 200, 200, 0, 0, 0, NULL);
5354 ok (hparent != 0, "Failed to create parent window\n");
5355 flush_sequence();
5356
5357 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5358 0, 0, 10, 10, hparent, 0, 0, NULL);
5359 ok (hchild != 0, "Failed to create child window\n");
5360 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5361 DestroyWindow(hchild);
5362 flush_sequence();
5363
5364 /* visible child window with a caption */
5365 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5366 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5367 0, 0, 10, 10, hparent, 0, 0, NULL);
5368 ok (hchild != 0, "Failed to create child window\n");
5369 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5370
5371 trace("testing scroll APIs on a visible child window %p\n", hchild);
5372 test_scroll_messages(hchild);
5373
5374 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5375 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5376
5377 DestroyWindow(hchild);
5378 flush_sequence();
5379
5380 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5381 0, 0, 10, 10, hparent, 0, 0, NULL);
5382 ok (hchild != 0, "Failed to create child window\n");
5383 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5384
5385 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5386 100, 100, 50, 50, hparent, 0, 0, NULL);
5387 ok (hchild2 != 0, "Failed to create child2 window\n");
5388 flush_sequence();
5389
5390 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5391 0, 100, 50, 50, hchild, 0, 0, NULL);
5392 ok (hbutton != 0, "Failed to create button window\n");
5393
5394 /* test WM_SETREDRAW on a not visible child window */
5395 test_WM_SETREDRAW(hchild);
5396
5397 ShowWindow(hchild, SW_SHOW);
5398 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5399
5400 /* check parent messages too */
5401 log_all_parent_messages++;
5402 ShowWindow(hchild, SW_HIDE);
5403 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5404 log_all_parent_messages--;
5405
5406 ShowWindow(hchild, SW_SHOW);
5407 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5408
5409 ShowWindow(hchild, SW_HIDE);
5410 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5411
5412 ShowWindow(hchild, SW_SHOW);
5413 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5414
5415 /* test WM_SETREDRAW on a visible child window */
5416 test_WM_SETREDRAW(hchild);
5417
5418 log_all_parent_messages++;
5419 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5420 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5421 log_all_parent_messages--;
5422
5423 ShowWindow(hchild, SW_HIDE);
5424 flush_sequence();
5425 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5426 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5427
5428 ShowWindow(hchild, SW_HIDE);
5429 flush_sequence();
5430 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5431 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5432
5433 /* DestroyWindow sequence below expects that a child has focus */
5434 SetFocus(hchild);
5435 flush_sequence();
5436
5437 DestroyWindow(hchild);
5438 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5439 DestroyWindow(hchild2);
5440 DestroyWindow(hbutton);
5441
5442 flush_sequence();
5443 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5444 0, 0, 100, 100, hparent, 0, 0, NULL);
5445 ok (hchild != 0, "Failed to create child popup window\n");
5446 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5447 DestroyWindow(hchild);
5448
5449 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5450 flush_sequence();
5451 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5452 0, 0, 100, 100, hparent, 0, 0, NULL);
5453 ok (hchild != 0, "Failed to create popup window\n");
5454 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5455 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5456 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5457 flush_sequence();
5458 ShowWindow(hchild, SW_SHOW);
5459 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5460 flush_sequence();
5461 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5462 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5463 flush_sequence();
5464 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5465 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5466 DestroyWindow(hchild);
5467
5468 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5469 * changes nothing in message sequences.
5470 */
5471 flush_sequence();
5472 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5473 0, 0, 100, 100, hparent, 0, 0, NULL);
5474 ok (hchild != 0, "Failed to create popup window\n");
5475 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5476 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5477 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5478 flush_sequence();
5479 ShowWindow(hchild, SW_SHOW);
5480 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5481 flush_sequence();
5482 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5483 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5484 DestroyWindow(hchild);
5485
5486 flush_sequence();
5487 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5488 0, 0, 100, 100, hparent, 0, 0, NULL);
5489 ok(hwnd != 0, "Failed to create custom dialog window\n");
5490 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5491
5492 if(0) {
5493 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5494 test_scroll_messages(hwnd);
5495 }
5496
5497 flush_sequence();
5498
5499 test_def_id = TRUE;
5500 SendMessageA(hwnd, WM_NULL, 0, 0);
5501
5502 flush_sequence();
5503 after_end_dialog = TRUE;
5504 EndDialog( hwnd, 0 );
5505 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5506
5507 DestroyWindow(hwnd);
5508 after_end_dialog = FALSE;
5509 test_def_id = FALSE;
5510
5511 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5512 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5513
5514 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5515 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5516 ok(hwnd != 0, "Failed to create custom dialog window\n");
5517 flush_sequence();
5518 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5519 ShowWindow(hwnd, SW_SHOW);
5520 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5521
5522 flush_events();
5523 flush_sequence();
5524 ret = DrawMenuBar(hwnd);
5525 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5526 flush_events();
5527 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5528 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5529
5530 DestroyWindow(hwnd);
5531
5532 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5533 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5534 ok(hwnd != 0, "Failed to create custom dialog window\n");
5535 flush_events();
5536 flush_sequence();
5537 ret = DrawMenuBar(hwnd);
5538 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5539 flush_events();
5540 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5541
5542 DestroyWindow(hwnd);
5543
5544 flush_sequence();
5545 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5546 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5547
5548 DestroyWindow(hparent);
5549 flush_sequence();
5550
5551 /* Message sequence for SetMenu */
5552 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5553 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5554 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5555
5556 hmenu = CreateMenu();
5557 ok (hmenu != 0, "Failed to create menu\n");
5558 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5559 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5560 100, 100, 200, 200, 0, hmenu, 0, NULL);
5561 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5562 ok (SetMenu(hwnd, 0), "SetMenu\n");
5563 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5564 ok (SetMenu(hwnd, 0), "SetMenu\n");
5565 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5566 ShowWindow(hwnd, SW_SHOW);
5567 UpdateWindow( hwnd );
5568 flush_events();
5569 flush_sequence();
5570 ok (SetMenu(hwnd, 0), "SetMenu\n");
5571 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5572 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5573 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5574
5575 UpdateWindow( hwnd );
5576 flush_events();
5577 flush_sequence();
5578 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5579 flush_events();
5580 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5581
5582 DestroyWindow(hwnd);
5583 flush_sequence();
5584
5585 /* Message sequence for EnableWindow */
5586 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5587 100, 100, 200, 200, 0, 0, 0, NULL);
5588 ok (hparent != 0, "Failed to create parent window\n");
5589 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5590 0, 0, 10, 10, hparent, 0, 0, NULL);
5591 ok (hchild != 0, "Failed to create child window\n");
5592
5593 SetFocus(hchild);
5594 flush_events();
5595 flush_sequence();
5596
5597 EnableWindow(hparent, FALSE);
5598 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5599
5600 EnableWindow(hparent, FALSE);
5601 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5602
5603 EnableWindow(hparent, TRUE);
5604 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5605
5606 EnableWindow(hparent, TRUE);
5607 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5608
5609 flush_events();
5610 flush_sequence();
5611
5612 test_MsgWaitForMultipleObjects(hparent);
5613 test_WM_DEVICECHANGE(hparent);
5614
5615 /* the following test causes an exception in user.exe under win9x */
5616 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5617 {
5618 DestroyWindow(hparent);
5619 flush_sequence();
5620 return;
5621 }
5622 PostMessageW( hparent, WM_USER+1, 0, 0 );
5623 /* PeekMessage(NULL) fails, but still removes the message */
5624 SetLastError(0xdeadbeef);
5625 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5626 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5627 GetLastError() == 0xdeadbeef, /* NT4 */
5628 "last error is %d\n", GetLastError() );
5629 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5630 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5631
5632 DestroyWindow(hchild);
5633 DestroyWindow(hparent);
5634 flush_sequence();
5635
5636 /* Message sequences for WM_SETICON */
5637 trace("testing WM_SETICON\n");
5638 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5639 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5640 NULL, NULL, 0);
5641 ShowWindow(hwnd, SW_SHOW);
5642 UpdateWindow(hwnd);
5643 flush_events();
5644 flush_sequence();
5645 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5646 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5647
5648 ShowWindow(hwnd, SW_HIDE);
5649 flush_events();
5650 flush_sequence();
5651 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5652 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5653 DestroyWindow(hwnd);
5654 flush_sequence();
5655
5656 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5657 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5658 NULL, NULL, 0);
5659 ShowWindow(hwnd, SW_SHOW);
5660 UpdateWindow(hwnd);
5661 flush_events();
5662 flush_sequence();
5663 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5664 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5665
5666 ShowWindow(hwnd, SW_HIDE);
5667 flush_events();
5668 flush_sequence();
5669 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5670 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5671
5672 flush_sequence();
5673 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5674 if (!res)
5675 {
5676 todo_wine win_skip( "Message 0x3b not supported\n" );
5677 goto done;
5678 }
5679 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5680 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5681 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5682 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5683 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5684 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5685 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5686 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5687
5688 flush_sequence();
5689 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5690 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5691 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5692 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5693 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5694 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5695
5696 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5697 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5698 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5699
5700 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5701 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5702 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5703
5704 done:
5705 DestroyWindow(hwnd);
5706 flush_sequence();
5707 }
5708
5709 static void test_setwindowpos(void)
5710 {
5711 HWND hwnd;
5712 RECT rc;
5713 LRESULT res;
5714 const INT winX = 100;
5715 const INT winY = 100;
5716 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5717
5718 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5719 0, 0, winX, winY, 0,
5720 NULL, NULL, 0);
5721
5722 GetWindowRect(hwnd, &rc);
5723 expect(sysX, rc.right);
5724 expect(winY, rc.bottom);
5725
5726 flush_events();
5727 flush_sequence();
5728 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5729 ok_sequence(WmZOrder, "Z-Order", TRUE);
5730 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5731
5732 GetWindowRect(hwnd, &rc);
5733 expect(sysX, rc.right);
5734 expect(winY, rc.bottom);
5735 DestroyWindow(hwnd);
5736 }
5737
5738 static void invisible_parent_tests(void)
5739 {
5740 HWND hparent, hchild;
5741
5742 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5743 100, 100, 200, 200, 0, 0, 0, NULL);
5744 ok (hparent != 0, "Failed to create parent window\n");
5745 flush_sequence();
5746
5747 /* test showing child with hidden parent */
5748
5749 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5750 0, 0, 10, 10, hparent, 0, 0, NULL);
5751 ok (hchild != 0, "Failed to create child window\n");
5752 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5753
5754 ShowWindow( hchild, SW_MINIMIZE );
5755 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5756 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5757 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5758
5759 /* repeat */
5760 flush_events();
5761 flush_sequence();
5762 ShowWindow( hchild, SW_MINIMIZE );
5763 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5764
5765 DestroyWindow(hchild);
5766 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5767 0, 0, 10, 10, hparent, 0, 0, NULL);
5768 flush_sequence();
5769
5770 ShowWindow( hchild, SW_MAXIMIZE );
5771 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5772 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5773 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5774
5775 /* repeat */
5776 flush_events();
5777 flush_sequence();
5778 ShowWindow( hchild, SW_MAXIMIZE );
5779 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5780
5781 DestroyWindow(hchild);
5782 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5783 0, 0, 10, 10, hparent, 0, 0, NULL);
5784 flush_sequence();
5785
5786 ShowWindow( hchild, SW_RESTORE );
5787 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5788 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5789 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5790
5791 DestroyWindow(hchild);
5792 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5793 0, 0, 10, 10, hparent, 0, 0, NULL);
5794 flush_sequence();
5795
5796 ShowWindow( hchild, SW_SHOWMINIMIZED );
5797 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5798 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5799 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5800
5801 /* repeat */
5802 flush_events();
5803 flush_sequence();
5804 ShowWindow( hchild, SW_SHOWMINIMIZED );
5805 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
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 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5813 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5814 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5815 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5816 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5817
5818 DestroyWindow(hchild);
5819 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5820 0, 0, 10, 10, hparent, 0, 0, NULL);
5821 flush_sequence();
5822
5823 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5824 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5825 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5826 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5827
5828 /* repeat */
5829 flush_events();
5830 flush_sequence();
5831 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5832 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5833
5834 DestroyWindow(hchild);
5835 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5836 0, 0, 10, 10, hparent, 0, 0, NULL);
5837 flush_sequence();
5838
5839 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5840 ShowWindow( hchild, SW_FORCEMINIMIZE );
5841 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5842 todo_wine {
5843 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5844 }
5845 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5846
5847 DestroyWindow(hchild);
5848 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5849 0, 0, 10, 10, hparent, 0, 0, NULL);
5850 flush_sequence();
5851
5852 ShowWindow( hchild, SW_SHOWNA );
5853 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5854 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5855 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5856
5857 /* repeat */
5858 flush_events();
5859 flush_sequence();
5860 ShowWindow( hchild, SW_SHOWNA );
5861 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5862
5863 DestroyWindow(hchild);
5864 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5865 0, 0, 10, 10, hparent, 0, 0, NULL);
5866 flush_sequence();
5867
5868 ShowWindow( hchild, SW_SHOW );
5869 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5870 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5871 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5872
5873 /* repeat */
5874 flush_events();
5875 flush_sequence();
5876 ShowWindow( hchild, SW_SHOW );
5877 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5878
5879 ShowWindow( hchild, SW_HIDE );
5880 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5881 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5882 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5883
5884 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5885 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5886 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5887 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5888
5889 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5890 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5891 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5892 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5893
5894 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5895 flush_sequence();
5896 DestroyWindow(hchild);
5897 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5898
5899 DestroyWindow(hparent);
5900 flush_sequence();
5901 }
5902
5903 /****************** button message test *************************/
5904 #define ID_BUTTON 0x000e
5905
5906 static const struct message WmSetFocusButtonSeq[] =
5907 {
5908 { HCBT_SETFOCUS, hook },
5909 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5910 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5911 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5912 { WM_SETFOCUS, sent|wparam, 0 },
5913 { WM_CTLCOLORBTN, sent|parent },
5914 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5915 { WM_APP, sent|wparam|lparam, 0, 0 },
5916 { 0 }
5917 };
5918 static const struct message WmKillFocusButtonSeq[] =
5919 {
5920 { HCBT_SETFOCUS, hook },
5921 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5922 { WM_KILLFOCUS, sent|wparam, 0 },
5923 { WM_CTLCOLORBTN, sent|parent },
5924 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5925 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5926 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5927 { WM_APP, sent|wparam|lparam, 0, 0 },
5928 { WM_PAINT, sent },
5929 { WM_CTLCOLORBTN, sent|parent },
5930 { 0 }
5931 };
5932 static const struct message WmSetFocusStaticSeq[] =
5933 {
5934 { HCBT_SETFOCUS, hook },
5935 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5936 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5937 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5938 { WM_SETFOCUS, sent|wparam, 0 },
5939 { WM_CTLCOLORSTATIC, sent|parent },
5940 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5941 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5942 { WM_APP, sent|wparam|lparam, 0, 0 },
5943 { 0 }
5944 };
5945 static const struct message WmKillFocusStaticSeq[] =
5946 {
5947 { HCBT_SETFOCUS, hook },
5948 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5949 { WM_KILLFOCUS, sent|wparam, 0 },
5950 { WM_CTLCOLORSTATIC, sent|parent },
5951 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5952 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5953 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5954 { WM_APP, sent|wparam|lparam, 0, 0 },
5955 { WM_PAINT, sent },
5956 { WM_CTLCOLORSTATIC, sent|parent },
5957 { 0 }
5958 };
5959 static const struct message WmSetFocusOwnerdrawSeq[] =
5960 {
5961 { HCBT_SETFOCUS, hook },
5962 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5963 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5964 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5965 { WM_SETFOCUS, sent|wparam, 0 },
5966 { WM_CTLCOLORBTN, sent|parent },
5967 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5968 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5969 { WM_APP, sent|wparam|lparam, 0, 0 },
5970 { 0 }
5971 };
5972 static const struct message WmKillFocusOwnerdrawSeq[] =
5973 {
5974 { HCBT_SETFOCUS, hook },
5975 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5976 { WM_KILLFOCUS, sent|wparam, 0 },
5977 { WM_CTLCOLORBTN, sent|parent },
5978 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5979 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5980 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5981 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5982 { WM_APP, sent|wparam|lparam, 0, 0 },
5983 { WM_PAINT, sent },
5984 { WM_CTLCOLORBTN, sent|parent },
5985 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5986 { 0 }
5987 };
5988 static const struct message WmLButtonDownSeq[] =
5989 {
5990 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5991 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5992 { HCBT_SETFOCUS, hook },
5993 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5994 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5995 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5996 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5997 { WM_CTLCOLORBTN, sent|defwinproc },
5998 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5999 { WM_CTLCOLORBTN, sent|defwinproc },
6000 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6001 { 0 }
6002 };
6003 static const struct message WmLButtonDownStaticSeq[] =
6004 {
6005 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6006 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6007 { HCBT_SETFOCUS, hook },
6008 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6009 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6010 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6011 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6012 { WM_CTLCOLORSTATIC, sent|defwinproc },
6013 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6014 { WM_CTLCOLORSTATIC, sent|defwinproc },
6015 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6016 { 0 }
6017 };
6018 static const struct message WmLButtonUpSeq[] =
6019 {
6020 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6021 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6022 { WM_CTLCOLORBTN, sent|defwinproc },
6023 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6024 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6025 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6026 { 0 }
6027 };
6028 static const struct message WmLButtonUpStaticSeq[] =
6029 {
6030 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6031 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6032 { WM_CTLCOLORSTATIC, sent|defwinproc },
6033 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6034 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6035 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6036 { 0 }
6037 };
6038 static const struct message WmLButtonUpAutoSeq[] =
6039 {
6040 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6041 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6042 { WM_CTLCOLORSTATIC, sent|defwinproc },
6043 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6044 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6045 { BM_SETCHECK, sent|defwinproc },
6046 { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6047 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6048 { 0 }
6049 };
6050 static const struct message WmLButtonUpBrokenSeq[] =
6051 {
6052 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6053 { 0 }
6054 };
6055 static const struct message WmSetFontButtonSeq[] =
6056 {
6057 { WM_SETFONT, sent },
6058 { WM_PAINT, sent },
6059 { WM_ERASEBKGND, sent|defwinproc|optional },
6060 { WM_CTLCOLORBTN, sent|defwinproc },
6061 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6062 { 0 }
6063 };
6064 static const struct message WmSetFontStaticSeq[] =
6065 {
6066 { WM_SETFONT, sent },
6067 { WM_PAINT, sent },
6068 { WM_ERASEBKGND, sent|defwinproc|optional },
6069 { WM_CTLCOLORSTATIC, sent|defwinproc },
6070 { 0 }
6071 };
6072 static const struct message WmSetTextButtonSeq[] =
6073 {
6074 { WM_SETTEXT, sent },
6075 { WM_CTLCOLORBTN, sent|parent },
6076 { WM_CTLCOLORBTN, sent|parent },
6077 { WM_COMMAND, sent|parent|optional },
6078 { WM_DRAWITEM, sent|parent|optional },
6079 { 0 }
6080 };
6081 static const struct message WmSetTextStaticSeq[] =
6082 {
6083 { WM_SETTEXT, sent },
6084 { WM_CTLCOLORSTATIC, sent|parent },
6085 { WM_CTLCOLORSTATIC, sent|parent },
6086 { 0 }
6087 };
6088 static const struct message WmSetTextGroupSeq[] =
6089 {
6090 { WM_SETTEXT, sent },
6091 { WM_CTLCOLORSTATIC, sent|parent },
6092 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6093 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6094 { 0 }
6095 };
6096 static const struct message WmSetTextInvisibleSeq[] =
6097 {
6098 { WM_SETTEXT, sent },
6099 { 0 }
6100 };
6101 static const struct message WmSetStyleButtonSeq[] =
6102 {
6103 { BM_SETSTYLE, sent },
6104 { WM_APP, sent|wparam|lparam, 0, 0 },
6105 { WM_PAINT, sent },
6106 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6107 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6108 { WM_CTLCOLORBTN, sent|parent },
6109 { 0 }
6110 };
6111 static const struct message WmSetStyleStaticSeq[] =
6112 {
6113 { BM_SETSTYLE, sent },
6114 { WM_APP, sent|wparam|lparam, 0, 0 },
6115 { WM_PAINT, sent },
6116 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6117 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6118 { WM_CTLCOLORSTATIC, sent|parent },
6119 { 0 }
6120 };
6121 static const struct message WmSetStyleUserSeq[] =
6122 {
6123 { BM_SETSTYLE, sent },
6124 { WM_APP, sent|wparam|lparam, 0, 0 },
6125 { WM_PAINT, sent },
6126 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6127 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6128 { WM_CTLCOLORBTN, sent|parent },
6129 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6130 { 0 }
6131 };
6132 static const struct message WmSetStyleOwnerdrawSeq[] =
6133 {
6134 { BM_SETSTYLE, sent },
6135 { WM_APP, sent|wparam|lparam, 0, 0 },
6136 { WM_PAINT, sent },
6137 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6138 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6139 { WM_CTLCOLORBTN, sent|parent },
6140 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6141 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6142 { 0 }
6143 };
6144 static const struct message WmSetStateButtonSeq[] =
6145 {
6146 { BM_SETSTATE, sent },
6147 { WM_CTLCOLORBTN, sent|parent },
6148 { WM_APP, sent|wparam|lparam, 0, 0 },
6149 { 0 }
6150 };
6151 static const struct message WmSetStateStaticSeq[] =
6152 {
6153 { BM_SETSTATE, sent },
6154 { WM_CTLCOLORSTATIC, sent|parent },
6155 { WM_APP, sent|wparam|lparam, 0, 0 },
6156 { 0 }
6157 };
6158 static const struct message WmSetStateUserSeq[] =
6159 {
6160 { BM_SETSTATE, sent },
6161 { WM_CTLCOLORBTN, sent|parent },
6162 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6163 { WM_APP, sent|wparam|lparam, 0, 0 },
6164 { 0 }
6165 };
6166 static const struct message WmSetStateOwnerdrawSeq[] =
6167 {
6168 { BM_SETSTATE, sent },
6169 { WM_CTLCOLORBTN, sent|parent },
6170 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6171 { WM_APP, sent|wparam|lparam, 0, 0 },
6172 { 0 }
6173 };
6174 static const struct message WmClearStateButtonSeq[] =
6175 {
6176 { BM_SETSTATE, sent },
6177 { WM_CTLCOLORBTN, sent|parent },
6178 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6179 { WM_APP, sent|wparam|lparam, 0, 0 },
6180 { 0 }
6181 };
6182 static const struct message WmDisableButtonSeq[] =
6183 {
6184 { WM_LBUTTONDOWN, sent },
6185 { BM_SETSTATE, sent|defwinproc },
6186 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6187 { WM_CTLCOLORBTN, sent|optional },
6188 { WM_LBUTTONUP, sent },
6189 { BM_SETSTATE, sent|defwinproc },
6190 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6191 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6192 { BM_SETCHECK, sent|defwinproc|optional },
6193 { WM_CTLCOLORBTN, sent|optional },
6194 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6195 { WM_CAPTURECHANGED, sent|defwinproc },
6196 { WM_COMMAND, sent },
6197 { 0 }
6198 };
6199 static const struct message WmClearStateOwnerdrawSeq[] =
6200 {
6201 { BM_SETSTATE, sent },
6202 { WM_CTLCOLORBTN, sent|parent },
6203 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6204 { WM_APP, sent|wparam|lparam, 0, 0 },
6205 { 0 }
6206 };
6207 static const struct message WmSetCheckIgnoredSeq[] =
6208 {
6209 { BM_SETCHECK, sent },
6210 { WM_APP, sent|wparam|lparam, 0, 0 },
6211 { 0 }
6212 };
6213 static const struct message WmSetCheckStaticSeq[] =
6214 {
6215 { BM_SETCHECK, sent },
6216 { WM_CTLCOLORSTATIC, sent|parent },
6217 { WM_APP, sent|wparam|lparam, 0, 0 },
6218 { 0 }
6219 };
6220
6221 static WNDPROC old_button_proc;
6222
6223 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6224 {
6225 static LONG defwndproc_counter = 0;
6226 LRESULT ret;
6227 struct recvd_message msg;
6228
6229 if (ignore_message( message )) return 0;
6230
6231 switch (message)
6232 {
6233 case WM_SYNCPAINT:
6234 break;
6235 case BM_SETSTATE:
6236 if (GetCapture())
6237 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6238
6239 lParam = (ULONG_PTR)GetMenu(hwnd);
6240 goto log_it;
6241
6242 case WM_GETDLGCODE:
6243 if (lParam)
6244 {
6245 MSG *msg = (MSG *)lParam;
6246 lParam = MAKELPARAM(msg->message, msg->wParam);
6247 }
6248 wParam = (ULONG_PTR)GetMenu(hwnd);
6249 goto log_it;
6250
6251 case BM_SETCHECK:
6252 case BM_GETCHECK:
6253 lParam = (ULONG_PTR)GetMenu(hwnd);
6254 /* fall through */
6255 log_it:
6256 default:
6257 msg.hwnd = hwnd;
6258 msg.message = message;
6259 msg.flags = sent|wparam|lparam;
6260 if (defwndproc_counter) msg.flags |= defwinproc;
6261 msg.wParam = wParam;
6262 msg.lParam = lParam;
6263 msg.descr = "button";
6264 add_message(&msg);
6265 }
6266
6267 defwndproc_counter++;
6268 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6269 defwndproc_counter--;
6270
6271 return ret;
6272 }
6273
6274 static void subclass_button(void)
6275 {
6276 WNDCLASSA cls;
6277
6278 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6279
6280 old_button_proc = cls.lpfnWndProc;
6281
6282 cls.hInstance = GetModuleHandleA(NULL);
6283 cls.lpfnWndProc = button_hook_proc;
6284 cls.lpszClassName = "my_button_class";
6285 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6286 if (!RegisterClassA(&cls)) assert(0);
6287 }
6288
6289 static void test_button_messages(void)
6290 {
6291 static const struct
6292 {
6293 DWORD style;
6294 DWORD dlg_code;
6295 const struct message *setfocus;
6296 const struct message *killfocus;
6297 const struct message *setstyle;
6298 const struct message *setstate;
6299 const struct message *clearstate;
6300 const struct message *setcheck;
6301 const struct message *lbuttondown;
6302 const struct message *lbuttonup;
6303 const struct message *setfont;
6304 const struct message *settext;
6305 } button[] = {
6306 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6307 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6308 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6309 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6310 WmSetTextButtonSeq },
6311 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6312 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6313 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6314 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6315 WmSetTextButtonSeq },
6316 { BS_CHECKBOX, DLGC_BUTTON,
6317 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6318 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6319 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6320 WmSetTextStaticSeq },
6321 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6322 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6323 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6324 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6325 WmSetTextStaticSeq },
6326 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6327 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6328 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6329 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6330 WmSetTextStaticSeq },
6331 { BS_3STATE, DLGC_BUTTON,
6332 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6333 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6334 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6335 WmSetTextStaticSeq },
6336 { BS_AUTO3STATE, DLGC_BUTTON,
6337 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6338 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6339 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6340 WmSetTextStaticSeq },
6341 { BS_GROUPBOX, DLGC_STATIC,
6342 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6343 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6344 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6345 WmSetTextGroupSeq },
6346 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6347 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6348 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6349 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6350 WmSetTextButtonSeq },
6351 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6352 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6353 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6354 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6355 WmSetTextStaticSeq },
6356 { BS_OWNERDRAW, DLGC_BUTTON,
6357 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6358 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6359 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6360 WmSetTextButtonSeq },
6361 };
6362 LOGFONTA logfont = { 0 };
6363 HFONT zfont, hfont2;
6364 unsigned int i;
6365 HWND hwnd, parent;
6366 DWORD dlg_code;
6367
6368 /* selection with VK_SPACE should capture button window */
6369 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6370 0, 0, 50, 14, 0, 0, 0, NULL);
6371 ok(hwnd != 0, "Failed to create button window\n");
6372 ReleaseCapture();
6373 SetFocus(hwnd);
6374 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6375 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6376 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6377 DestroyWindow(hwnd);
6378
6379 subclass_button();
6380
6381 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6382 100, 100, 200, 200, 0, 0, 0, NULL);
6383 ok(parent != 0, "Failed to create parent window\n");
6384
6385 memset(&logfont, 0, sizeof(logfont));
6386 logfont.lfHeight = -12;
6387 logfont.lfWeight = FW_NORMAL;
6388 strcpy(logfont.lfFaceName, "Tahoma");
6389
6390 hfont2 = CreateFontIndirectA(&logfont);
6391 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6392
6393 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
6394 {
6395 MSG msg;
6396 DWORD style, state;
6397 HFONT prevfont;
6398 char desc[64];
6399 HDC hdc;
6400
6401 trace("button style %08x\n", button[i].style);
6402
6403 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6404 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6405 ok(hwnd != 0, "Failed to create button window\n");
6406
6407 style = GetWindowLongA(hwnd, GWL_STYLE);
6408 style &= ~(WS_CHILD | BS_NOTIFY);
6409 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6410 if (button[i].style == BS_USERBUTTON)
6411 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6412 else
6413 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6414
6415 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6416 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6417
6418 ShowWindow(hwnd, SW_SHOW);
6419 UpdateWindow(hwnd);
6420 SetFocus(0);
6421 flush_events();
6422 SetFocus(0);
6423 flush_sequence();
6424
6425 log_all_parent_messages++;
6426
6427 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6428 SetFocus(hwnd);
6429 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6430 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6431 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6432
6433 SetFocus(0);
6434 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6435 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6436 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6437
6438 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6439
6440 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6441 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6442 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6443 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6444
6445 style = GetWindowLongA(hwnd, GWL_STYLE);
6446 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6447 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6448 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6449
6450 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6451 ok(state == 0, "expected state 0, got %04x\n", state);
6452
6453 flush_sequence();
6454
6455 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6456 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6457 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6458 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6459
6460 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6461 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6462
6463 style = GetWindowLongA(hwnd, GWL_STYLE);
6464 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6465 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6466
6467 flush_sequence();
6468
6469 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6470 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6471 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6472 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6473
6474 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6475 ok(state == 0, "expected state 0, got %04x\n", state);
6476
6477 style = GetWindowLongA(hwnd, GWL_STYLE);
6478 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6479 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6480
6481 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6482 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6483
6484 flush_sequence();
6485
6486 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6487 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6488 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6489 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6490
6491 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6492 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6493
6494 style = GetWindowLongA(hwnd, GWL_STYLE);
6495 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6496 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6497
6498 flush_sequence();
6499
6500 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6501 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6502 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6503 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6504
6505 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6506 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6507 ok_sequence(button[i].settext, desc, FALSE);
6508
6509 ShowWindow(hwnd, SW_HIDE);
6510 flush_events();
6511 flush_sequence();
6512
6513 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6514 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6515 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6516
6517 ShowWindow(hwnd, SW_SHOW);
6518 ShowWindow(parent, SW_HIDE);
6519 flush_events();
6520 flush_sequence();
6521
6522 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6523 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6524 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6525
6526 ShowWindow(parent, SW_SHOW);
6527 flush_events();
6528
6529 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6530 if (button[i].style == BS_PUSHBUTTON ||
6531 button[i].style == BS_DEFPUSHBUTTON ||
6532 button[i].style == BS_GROUPBOX ||
6533 button[i].style == BS_USERBUTTON ||
6534 button[i].style == BS_OWNERDRAW)
6535 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6536 else
6537 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6538
6539 style = GetWindowLongA(hwnd, GWL_STYLE);
6540 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6541 if (button[i].style == BS_RADIOBUTTON ||
6542 button[i].style == BS_AUTORADIOBUTTON)
6543 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6544 else
6545 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6546
6547 log_all_parent_messages--;
6548
6549 DestroyWindow(hwnd);
6550
6551 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6552 0, 0, 50, 14, 0, 0, 0, NULL);
6553 ok(hwnd != 0, "Failed to create button window\n");
6554
6555 SetForegroundWindow(hwnd);
6556 flush_events();
6557
6558 SetActiveWindow(hwnd);
6559 SetFocus(0);
6560 flush_sequence();
6561
6562 if (button[i].lbuttondown)
6563 {
6564 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6565 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6566 ok_sequence(button[i].lbuttondown, desc, FALSE);
6567 }
6568
6569 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6570 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6571 ok_sequence(button[i].lbuttonup, desc, FALSE);
6572
6573 flush_sequence();
6574 zfont = GetStockObject(DEFAULT_GUI_FONT);
6575 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6576 UpdateWindow(hwnd);
6577 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6578 ok_sequence(button[i].setfont, desc, FALSE);
6579
6580 /* Test that original font is not selected back after painting */
6581 hdc = CreateCompatibleDC(0);
6582
6583 prevfont = SelectObject(hdc, hfont2);
6584 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6585 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6586 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6587 SelectObject(hdc, prevfont);
6588
6589 prevfont = SelectObject(hdc, hfont2);
6590 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6591 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6592 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6593 SelectObject(hdc, prevfont);
6594
6595 DeleteDC(hdc);
6596
6597 DestroyWindow(hwnd);
6598 }
6599
6600 DeleteObject(hfont2);
6601 DestroyWindow(parent);
6602
6603 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6604
6605 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6606 100, 100, 200, 200, 0, 0, 0, NULL);
6607 ok (hwnd != 0, "Failed to create overlapped window\n");
6608
6609 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6610 0, 0, 50, 14, parent, 0, 0, NULL);
6611
6612 EnableWindow(hwnd, FALSE);
6613 flush_sequence();
6614 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6615 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6616 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6617
6618 DestroyWindow(hwnd);
6619 DestroyWindow(parent);
6620 }
6621
6622 #define ID_RADIO1 501
6623 #define ID_RADIO2 502
6624 #define ID_RADIO3 503
6625 #define ID_TEXT 504
6626
6627 static const struct message auto_radio_button_BM_CLICK[] =
6628 {
6629 { BM_CLICK, sent|wparam|lparam, 0, 0 },
6630 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6631 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6632 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6633 { WM_CTLCOLORSTATIC, sent|parent },
6634 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6635 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6636 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6637 { WM_CTLCOLORSTATIC, sent|parent },
6638 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6639 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6640 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6641 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6642 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
6643 { WM_CTLCOLORSTATIC, sent|parent },
6644 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6645 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6646 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
6647 { WM_CTLCOLORSTATIC, sent|parent },
6648 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6649 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6650 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6651 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6652 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
6653 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6654 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6655 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6656 { 0 }
6657 };
6658
6659 static const struct message auto_radio_button_VK_UP_child[] =
6660 {
6661 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
6662 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
6663 { 0 }
6664 };
6665
6666 static const struct message auto_radio_button_VK_UP_parent[] =
6667 {
6668 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
6669 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
6670 { 0 }
6671 };
6672
6673 static const struct message auto_radio_button_VK_UP_dialog[] =
6674 {
6675 { WM_GETDLGCODE, sent|parent, 0, 0 },
6676
6677 /* optional trailer seen on some windows setups */
6678 { WM_CHANGEUISTATE, sent|optional },
6679 { WM_UPDATEUISTATE, sent|optional },
6680 { WM_UPDATEUISTATE, sent|optional },
6681 { WM_UPDATEUISTATE, sent|optional },
6682 { WM_UPDATEUISTATE, sent|optional },
6683 { WM_UPDATEUISTATE, sent|optional },
6684 { WM_UPDATEUISTATE, sent|optional },
6685 { WM_UPDATEUISTATE, sent|optional },
6686 { WM_UPDATEUISTATE, sent|optional },
6687 { WM_UPDATEUISTATE, sent|optional },
6688 { WM_UPDATEUISTATE, sent|optional },
6689 { WM_UPDATEUISTATE, sent|optional },
6690 { WM_UPDATEUISTATE, sent|optional },
6691 { WM_UPDATEUISTATE, sent|optional },
6692 { WM_UPDATEUISTATE, sent|optional },
6693 { WM_UPDATEUISTATE, sent|optional },
6694 { WM_UPDATEUISTATE, sent|optional },
6695 { WM_UPDATEUISTATE, sent|optional },
6696 { WM_UPDATEUISTATE, sent|optional },
6697 { WM_CTLCOLORSTATIC, sent|parent|optional },
6698 { WM_CTLCOLORSTATIC, sent|parent|optional },
6699 { WM_CTLCOLORSTATIC, sent|parent|optional },
6700 { WM_UPDATEUISTATE, sent|optional },
6701 { WM_CTLCOLORSTATIC, sent|parent|optional },
6702 { WM_CTLCOLORSTATIC, sent|parent|optional },
6703 { WM_UPDATEUISTATE, sent|optional },
6704 { WM_CTLCOLORBTN, sent|parent|optional },
6705 { WM_CTLCOLORBTN, sent|parent|optional },
6706 { WM_UPDATEUISTATE, sent|optional },
6707 { WM_CTLCOLORSTATIC, sent|parent|optional },
6708 { WM_CTLCOLORSTATIC, sent|parent|optional },
6709 { 0 }
6710 };
6711
6712 static const struct message auto_radio_button_VK_DOWN_dialog[] =
6713 {
6714 { WM_GETDLGCODE, sent|parent, 0, 0 },
6715 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6716 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6717 { HCBT_SETFOCUS, hook },
6718 { WM_KILLFOCUS, sent, 0, 0 },
6719 { WM_CTLCOLORSTATIC, sent|parent },
6720 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
6721 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6722 { WM_SETFOCUS, sent, 0, 0 },
6723 { WM_CTLCOLORSTATIC, sent|parent },
6724 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
6725 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6726 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6727 { WM_GETDLGCODE, sent|parent, 0, 0 },
6728 { DM_GETDEFID, sent|parent, 0, 0 },
6729 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6730 { BM_CLICK, sent|wparam|lparam, 1, 0 },
6731 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6732 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6733 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6734 { WM_CTLCOLORSTATIC, sent|parent },
6735 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6736 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6737 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
6738 { WM_CTLCOLORSTATIC, sent|parent },
6739 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6740 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6741 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6742 { WM_CTLCOLORSTATIC, sent|parent },
6743 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6744 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6745 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
6746 { WM_CTLCOLORSTATIC, sent|parent },
6747 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6748 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6749 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6750 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6751 { WM_CTLCOLORSTATIC, sent|parent },
6752 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6753 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6754 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6755 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6756 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6757 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6758 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6759 { WM_PAINT, sent },
6760 { WM_CTLCOLORSTATIC, sent|parent },
6761 { 0 }
6762 };
6763
6764 static const struct message auto_radio_button_VK_DOWN_radio3[] =
6765 {
6766 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6767 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
6768 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
6769 { WM_GETDLGCODE, sent|parent, 0, 0 },
6770 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6771 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6772 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6773 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
6774 { WM_USER, sent|parent, 0, 0 },
6775 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6776 { 0 }
6777 };
6778
6779 static const struct message auto_radio_button_VK_UP_radio1[] =
6780 {
6781 { WM_GETDLGCODE, sent|parent, 0, 0 },
6782 { 0 }
6783 };
6784
6785 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
6786 {
6787 ParentMsgCheckProcA(hwnd, msg, wp, lp);
6788 return 1;
6789 }
6790
6791 static void test_autoradio_BM_CLICK(void)
6792 {
6793 HWND parent, radio1, radio2, radio3;
6794 RECT rc;
6795 MSG msg;
6796 DWORD ret;
6797
6798 subclass_button();
6799
6800 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
6801 ok(parent != 0, "failed to create parent window\n");
6802
6803 radio1 = GetDlgItem(parent, ID_RADIO1);
6804 radio2 = GetDlgItem(parent, ID_RADIO2);
6805 radio3 = GetDlgItem(parent, ID_RADIO3);
6806
6807 /* this avoids focus messages in the generated sequence */
6808 SetFocus(radio2);
6809
6810 flush_events();
6811 flush_sequence();
6812
6813 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6814 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6815 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6816 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6817 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6818 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6819
6820 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
6821
6822 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6823 ok(ret == BST_CHECKED, "got %08x\n", ret);
6824 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6825 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6826 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6827 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6828
6829 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
6830
6831 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6832 ok(ret == BST_CHECKED, "got %08x\n", ret);
6833 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6834 ok(ret == BST_CHECKED, "got %08x\n", ret);
6835 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6836 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6837
6838 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
6839
6840 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6841 ok(ret == BST_CHECKED, "got %08x\n", ret);
6842 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6843 ok(ret == BST_CHECKED, "got %08x\n", ret);
6844 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6845 ok(ret == BST_CHECKED, "got %08x\n", ret);
6846
6847 GetWindowRect(radio2, &rc);
6848 SetCursorPos(rc.left+1, rc.top+1);
6849
6850 flush_events();
6851 flush_sequence();
6852
6853 log_all_parent_messages++;
6854
6855 SendMessageA(radio2, BM_CLICK, 0, 0);
6856 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6857 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
6858
6859 log_all_parent_messages--;
6860
6861 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6862 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6863 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6864 ok(ret == BST_CHECKED, "got %08x\n", ret);
6865 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6866 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6867
6868 DestroyWindow(parent);
6869 }
6870
6871 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
6872 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
6873 {
6874 DWORD ret;
6875
6876 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6877 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6878 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6879 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6880 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6881 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6882 }
6883
6884 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
6885 {
6886 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
6887 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
6888 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
6889 }
6890
6891 static void test_autoradio_kbd_move(void)
6892 {
6893 HWND parent, radio1, radio2, radio3, hwnd;
6894 RECT rc;
6895 MSG msg;
6896 DWORD ret;
6897
6898 subclass_button();
6899
6900 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
6901 ok(parent != 0, "failed to create parent window\n");
6902
6903 radio1 = GetDlgItem(parent, ID_RADIO1);
6904 radio2 = GetDlgItem(parent, ID_RADIO2);
6905 radio3 = GetDlgItem(parent, ID_RADIO3);
6906
6907 flush_events();
6908 flush_sequence();
6909
6910 test_radio(radio1, 0, radio2, 0, radio3, 0);
6911 set_radio(radio1, 1, radio2, 1, radio3, 1);
6912 test_radio(radio1, 1, radio2, 1, radio3, 1);
6913
6914 SetFocus(radio3);
6915
6916 flush_events();
6917 flush_sequence();
6918
6919 log_all_parent_messages++;
6920
6921 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
6922 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
6923 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6924 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
6925
6926 test_radio(radio1, 1, radio2, 1, radio3, 1);
6927
6928 flush_events();
6929 flush_sequence();
6930
6931 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
6932 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
6933 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6934 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
6935
6936 test_radio(radio1, 1, radio2, 1, radio3, 1);
6937
6938 SetFocus(radio3);
6939 GetWindowRect(radio3, &rc);
6940
6941 flush_events();
6942 flush_sequence();
6943
6944 msg.hwnd = parent;
6945 msg.message = WM_KEYDOWN;
6946 msg.wParam = VK_UP;
6947 msg.lParam = 0;
6948 msg.pt.x = rc.left + 1;
6949 msg.pt.y = rc.top + 1;
6950 ret = IsDialogMessageA(parent, &msg);
6951 ok(ret, "IsDialogMessage should return TRUE\n");
6952 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6953 if (0) /* actual message sequence is different on every run in some Windows setups */
6954 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
6955 /* what really matters is that nothing has changed */
6956 test_radio(radio1, 1, radio2, 1, radio3, 1);
6957
6958 set_radio(radio1, 0, radio2, 1, radio3, 1);
6959 test_radio(radio1, 0, radio2, 1, radio3, 1);
6960
6961 flush_events();
6962 flush_sequence();
6963
6964 ret = IsDialogMessageA(parent, &msg);
6965 ok(ret, "IsDialogMessage should return TRUE\n");
6966 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6967 if (0) /* actual message sequence is different on every run in some Windows setups */
6968 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
6969 /* what really matters is that nothing has changed */
6970 test_radio(radio1, 0, radio2, 1, radio3, 1);
6971
6972 /* switch from radio3 ro radio1 */
6973 SetFocus(radio3);
6974 GetWindowRect(radio3, &rc);
6975
6976 flush_events();
6977 flush_sequence();
6978
6979 msg.hwnd = parent;
6980 msg.message = WM_KEYDOWN;
6981 msg.wParam = VK_DOWN;
6982 msg.lParam = 0;
6983 msg.pt.x = rc.left + 1;
6984 msg.pt.y = rc.top + 1;
6985 ret = IsDialogMessageA(parent, &msg);
6986 ok(ret, "IsDialogMessage should return TRUE\n");
6987 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6988 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
6989
6990 test_radio(radio1, 1, radio2, 0, radio3, 0);
6991
6992 hwnd = GetFocus();
6993 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
6994 GetWindowRect(radio1, &rc);
6995
6996 msg.hwnd = parent;
6997 msg.message = WM_KEYDOWN;
6998 msg.wParam = VK_DOWN;
6999 msg.lParam = 0;
7000 msg.pt.x = rc.left + 1;
7001 msg.pt.y = rc.top + 1;
7002 ret = IsDialogMessageA(parent, &msg);
7003 ok(ret, "IsDialogMessage should return TRUE\n");
7004 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7005 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7006
7007 test_radio(radio1, 1, radio2, 0, radio3, 0);
7008
7009 hwnd = GetFocus();
7010 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7011
7012 flush_events();
7013 flush_sequence();
7014
7015 msg.hwnd = parent;
7016 msg.message = WM_KEYDOWN;
7017 msg.wParam = VK_UP;
7018 msg.lParam = 0;
7019 msg.pt.x = rc.left + 1;
7020 msg.pt.y = rc.top + 1;
7021 ret = IsDialogMessageA(parent, &msg);
7022 ok(ret, "IsDialogMessage should return TRUE\n");
7023 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7024 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7025
7026 test_radio(radio1, 1, radio2, 0, radio3, 0);
7027
7028 hwnd = GetFocus();
7029 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7030
7031 flush_events();
7032 flush_sequence();
7033
7034 msg.hwnd = parent;
7035 msg.message = WM_KEYDOWN;
7036 msg.wParam = VK_UP;
7037 msg.lParam = 0;
7038 msg.pt.x = rc.left + 1;
7039 msg.pt.y = rc.top + 1;
7040 ret = IsDialogMessageA(parent, &msg);
7041 ok(ret, "IsDialogMessage should return TRUE\n");
7042 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7043 if (0) /* actual message sequence is different on every run in some Windows setups */
7044 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7045 /* what really matters is that nothing has changed */
7046 test_radio(radio1, 1, radio2, 0, radio3, 0);
7047
7048 log_all_parent_messages--;
7049
7050 DestroyWindow(parent);
7051 }
7052
7053 /****************** static message test *************************/
7054 static const struct message WmSetFontStaticSeq2[] =
7055 {
7056 { WM_SETFONT, sent },
7057 { WM_PAINT, sent|defwinproc|optional },
7058 { WM_ERASEBKGND, sent|defwinproc|optional },
7059 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7060 { 0 }
7061 };
7062
7063 static WNDPROC old_static_proc;
7064
7065 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7066 {
7067 static LONG defwndproc_counter = 0;
7068 LRESULT ret;
7069 struct recvd_message msg;
7070
7071 if (ignore_message( message )) return 0;
7072
7073 msg.hwnd = hwnd;
7074 msg.message = message;
7075 msg.flags = sent|wparam|lparam;
7076 if (defwndproc_counter) msg.flags |= defwinproc;
7077 msg.wParam = wParam;
7078 msg.lParam = lParam;
7079 msg.descr = "static";
7080 add_message(&msg);
7081
7082 defwndproc_counter++;
7083 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7084 defwndproc_counter--;
7085
7086 return ret;
7087 }
7088
7089 static void subclass_static(void)
7090 {
7091 WNDCLASSA cls;
7092
7093 if (!GetClassInfoA(0, "static", &cls)) assert(0);
7094
7095 old_static_proc = cls.lpfnWndProc;
7096
7097 cls.hInstance = GetModuleHandleA(NULL);
7098 cls.lpfnWndProc = static_hook_proc;
7099 cls.lpszClassName = "my_static_class";
7100 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7101 if (!RegisterClassA(&cls)) assert(0);
7102 }
7103
7104 static void test_static_messages(void)
7105 {
7106 /* FIXME: make as comprehensive as the button message test */
7107 static const struct
7108 {
7109 DWORD style;
7110 DWORD dlg_code;
7111 const struct message *setfont;
7112 } static_ctrl[] = {
7113 { SS_LEFT, DLGC_STATIC,
7114 WmSetFontStaticSeq2 }
7115 };
7116 unsigned int i;
7117 HWND hwnd;
7118 DWORD dlg_code;
7119
7120 subclass_static();
7121
7122 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
7123 {
7124 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7125 0, 0, 50, 14, 0, 0, 0, NULL);
7126 ok(hwnd != 0, "Failed to create static window\n");
7127
7128 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7129 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7130
7131 ShowWindow(hwnd, SW_SHOW);
7132 UpdateWindow(hwnd);
7133 SetFocus(0);
7134 flush_sequence();
7135
7136 trace("static style %08x\n", static_ctrl[i].style);
7137 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7138 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7139
7140 DestroyWindow(hwnd);
7141 }
7142 }
7143
7144 /****************** ComboBox message test *************************/
7145 #define ID_COMBOBOX 0x000f
7146
7147 static const struct message SetCurSelComboSeq[] =
7148 {
7149 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7150 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7151 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7152 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7153 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7154 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7155 { LB_GETTEXT, sent|wparam, 0 },
7156 { WM_CTLCOLOREDIT, sent|parent },
7157 { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7158 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7159 { 0 }
7160 };
7161
7162 static const struct message SetCurSelComboSeq2[] =
7163 {
7164 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7165 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7166 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7167 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7168 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7169 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7170 { LB_GETTEXT, sent|wparam, 0 },
7171 { 0 }
7172 };
7173
7174 static const struct message SetCurSelComboSeq_edit[] =
7175 {
7176 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7177 { WM_SETTEXT, sent|wparam, 0 },
7178 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7179 { 0 }
7180 };
7181
7182 static const struct message WmKeyDownComboSeq[] =
7183 {
7184 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7185 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7186 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7187 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7188 { WM_CTLCOLOREDIT, sent|parent },
7189 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7190 { 0 }
7191 };
7192
7193 static const struct message WmSetPosComboSeq[] =
7194 {
7195 { WM_WINDOWPOSCHANGING, sent },
7196 { WM_NCCALCSIZE, sent|wparam, TRUE },
7197 { WM_CHILDACTIVATE, sent },
7198 { WM_WINDOWPOSCHANGED, sent },
7199 { WM_MOVE, sent|defwinproc },
7200 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7201 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7202 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7203 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7204 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7205 { 0 }
7206 };
7207
7208 static const struct message WMSetFocusComboBoxSeq[] =
7209 {
7210 { WM_SETFOCUS, sent },
7211 { WM_KILLFOCUS, sent|parent },
7212 { WM_SETFOCUS, sent },
7213 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7214 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7215 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7216 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7217 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7218 { 0 }
7219 };
7220
7221 static const struct message SetFocusButtonSeq[] =
7222 {
7223 { WM_KILLFOCUS, sent },
7224 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7225 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7226 { WM_LBUTTONUP, sent|defwinproc },
7227 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7228 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7229 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7230 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7231 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7232 { WM_CTLCOLORBTN, sent|parent },
7233 { 0 }
7234 };
7235
7236 static const struct message SetFocusComboBoxSeq[] =
7237 {
7238 { WM_CTLCOLORBTN, sent|parent },
7239 { WM_SETFOCUS, sent },
7240 { WM_KILLFOCUS, sent|defwinproc },
7241 { WM_SETFOCUS, sent },
7242 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7243 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7244 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7245 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7246 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7247 { 0 }
7248 };
7249
7250 static const struct message SetFocusButtonSeq2[] =
7251 {
7252 { WM_KILLFOCUS, sent },
7253 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7254 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7255 { WM_LBUTTONUP, sent|defwinproc },
7256 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7257 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7258 { WM_CTLCOLOREDIT, sent|defwinproc },
7259 { WM_CTLCOLOREDIT, sent|parent },
7260 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7261 { WM_CTLCOLORBTN, sent|parent },
7262 { 0 }
7263 };
7264
7265 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7266
7267 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7268 WPARAM wParam, LPARAM lParam)
7269 {
7270 static LONG defwndproc_counter = 0;
7271 LRESULT ret;
7272 struct recvd_message msg;
7273
7274 /* do not log painting messages */
7275 if (message != WM_PAINT &&
7276 message != WM_NCPAINT &&
7277 message != WM_SYNCPAINT &&
7278 message != WM_ERASEBKGND &&
7279 message != WM_NCHITTEST &&
7280 message != WM_GETTEXT &&
7281 !ignore_message( message ))
7282 {
7283 msg.hwnd = hwnd;
7284 msg.message = message;
7285 msg.flags = sent|wparam|lparam;
7286 if (defwndproc_counter) msg.flags |= defwinproc;
7287 msg.wParam = wParam;
7288 msg.lParam = lParam;
7289 msg.descr = "combo edit";
7290 add_message(&msg);
7291 }
7292
7293 defwndproc_counter++;
7294 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7295 defwndproc_counter--;
7296
7297 return ret;
7298 }
7299
7300 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7301 WPARAM wParam, LPARAM lParam)
7302 {
7303 static LONG defwndproc_counter = 0;
7304 LRESULT ret;
7305 struct recvd_message msg;
7306
7307 /* do not log painting messages */
7308 if (message != WM_PAINT &&
7309 message != WM_NCPAINT &&
7310 message != WM_SYNCPAINT &&
7311 message != WM_ERASEBKGND &&
7312 message != WM_NCHITTEST &&
7313 !ignore_message( message ))
7314 {
7315 msg.hwnd = hwnd;
7316 msg.message = message;
7317 msg.flags = sent|wparam|lparam;
7318 if (defwndproc_counter) msg.flags |= defwinproc;
7319 msg.wParam = wParam;
7320 msg.lParam = lParam;
7321 msg.descr = "combo lbox";
7322 add_message(&msg);
7323 }
7324
7325 defwndproc_counter++;
7326 ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7327 defwndproc_counter--;
7328
7329 return ret;
7330 }
7331
7332 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7333 {
7334 static LONG defwndproc_counter = 0;
7335 LRESULT ret;
7336 struct recvd_message msg;
7337
7338 /* do not log painting messages */
7339 if (message != WM_PAINT &&
7340 message != WM_NCPAINT &&
7341 message != WM_SYNCPAINT &&
7342 message != WM_ERASEBKGND &&
7343 message != WM_NCHITTEST &&
7344 message != WM_GETTEXT &&
7345 !ignore_message( message ))
7346 {
7347 msg.hwnd = hwnd;
7348 msg.message = message;
7349 msg.flags = sent|wparam|lparam;
7350 if (defwndproc_counter) msg.flags |= defwinproc;
7351 msg.wParam = wParam;
7352 msg.lParam = lParam;
7353 msg.descr = "combo";
7354 add_message(&msg);
7355 }
7356
7357 defwndproc_counter++;
7358 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7359 defwndproc_counter--;
7360
7361 return ret;
7362 }
7363
7364 static void subclass_combobox(void)
7365 {
7366 WNDCLASSA cls;
7367
7368 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7369
7370 old_combobox_proc = cls.lpfnWndProc;
7371
7372 cls.hInstance = GetModuleHandleA(NULL);
7373 cls.lpfnWndProc = combobox_hook_proc;
7374 cls.lpszClassName = "my_combobox_class";
7375 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7376 if (!RegisterClassA(&cls)) assert(0);
7377 }
7378
7379 static void test_combobox_messages(void)
7380 {
7381 HWND parent, combo, button, edit, lbox;
7382 LRESULT ret;
7383 COMBOBOXINFO cbInfo;
7384 BOOL res;
7385
7386 subclass_combobox();
7387
7388 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7389 100, 100, 200, 200, 0, 0, 0, NULL);
7390 ok(parent != 0, "Failed to create parent window\n");
7391 flush_sequence();
7392
7393 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7394 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7395 ok(combo != 0, "Failed to create combobox window\n");
7396
7397 UpdateWindow(combo);
7398
7399 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7400 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7401
7402 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7403 ok(ret == 0, "expected 0, got %ld\n", ret);
7404 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7405 ok(ret == 1, "expected 1, got %ld\n", ret);
7406 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7407 ok(ret == 2, "expected 2, got %ld\n", ret);
7408
7409 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7410 SetFocus(combo);
7411 flush_sequence();
7412
7413 log_all_parent_messages++;
7414 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7415 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7416 log_all_parent_messages--;
7417 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7418
7419 flush_sequence();
7420 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7421 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7422
7423 DestroyWindow(combo);
7424 DestroyWindow(parent);
7425
7426 /* Start again. Test combobox text selection when getting and losing focus */
7427 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7428 10, 10, 300, 300, NULL, NULL, NULL, NULL);
7429 ok(parent != 0, "Failed to create parent window\n");
7430
7431 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7432 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7433 ok(combo != 0, "Failed to create combobox window\n");
7434
7435 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7436 SetLastError(0xdeadbeef);
7437 res = GetComboBoxInfo(combo, &cbInfo);
7438 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7439 edit = cbInfo.hwndItem;
7440
7441 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
7442 (ULONG_PTR)combobox_edit_subclass_proc);
7443
7444 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7445 5, 50, 100, 20, parent, NULL,
7446 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7447 ok(button != 0, "Failed to create button window\n");
7448
7449 flush_sequence();
7450 log_all_parent_messages++;
7451 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7452 log_all_parent_messages--;
7453 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7454
7455 flush_sequence();
7456 log_all_parent_messages++;
7457 SetFocus(button);
7458 log_all_parent_messages--;
7459 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7460
7461 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7462
7463 flush_sequence();
7464 log_all_parent_messages++;
7465 SetFocus(combo);
7466 log_all_parent_messages--;
7467 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7468
7469 flush_sequence();
7470 log_all_parent_messages++;
7471 SetFocus(button);
7472 log_all_parent_messages--;
7473 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7474
7475 SetFocus(combo);
7476 SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
7477 flush_sequence();
7478 log_all_parent_messages++;
7479 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7480 log_all_parent_messages--;
7481 ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
7482
7483 DestroyWindow(button);
7484 DestroyWindow(combo);
7485
7486 combo = CreateWindowExA(0, "my_combobox_class", "test",
7487 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
7488 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7489 ok(combo != 0, "Failed to create combobox window\n");
7490
7491 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7492 ok(ret == 0, "expected 0, got %ld\n", ret);
7493
7494 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7495 SetLastError(0xdeadbeef);
7496 res = GetComboBoxInfo(combo, &cbInfo);
7497 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7498 lbox = cbInfo.hwndList;
7499 lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
7500 (ULONG_PTR)combobox_lbox_subclass_proc);
7501 flush_sequence();
7502
7503 log_all_parent_messages++;
7504 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7505 log_all_parent_messages--;
7506 ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
7507
7508 ShowWindow(combo, SW_HIDE);
7509 flush_sequence();
7510 log_all_parent_messages++;
7511 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7512 log_all_parent_messages--;
7513 ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
7514
7515 DestroyWindow(combo);
7516 DestroyWindow(parent);
7517 }
7518
7519 /****************** WM_IME_KEYDOWN message test *******************/
7520
7521 static const struct message WmImeKeydownMsgSeq_0[] =
7522 {
7523 { WM_IME_KEYDOWN, wparam, VK_RETURN },
7524 { WM_CHAR, wparam, 'A' },
7525 { 0 }
7526 };
7527
7528 static const struct message WmImeKeydownMsgSeq_1[] =
7529 {
7530 { WM_KEYDOWN, optional|wparam, VK_RETURN },
7531 { WM_CHAR, optional|wparam, VK_RETURN },
7532 { 0 }
7533 };
7534
7535 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7536 {
7537 struct recvd_message msg;
7538
7539 msg.hwnd = hwnd;
7540 msg.message = message;
7541 msg.flags = wparam|lparam;
7542 msg.wParam = wParam;
7543 msg.lParam = lParam;
7544 msg.descr = "wmime_keydown";
7545 add_message(&msg);
7546
7547 return DefWindowProcA(hwnd, message, wParam, lParam);
7548 }
7549
7550 static void register_wmime_keydown_class(void)
7551 {
7552 WNDCLASSA cls;
7553
7554 ZeroMemory(&cls, sizeof(WNDCLASSA));
7555 cls.lpfnWndProc = wmime_keydown_procA;
7556 cls.hInstance = GetModuleHandleA(0);
7557 cls.lpszClassName = "wmime_keydown_class";
7558 if (!RegisterClassA(&cls)) assert(0);
7559 }
7560
7561 static void test_wmime_keydown_message(void)
7562 {
7563 HWND hwnd;
7564 MSG msg;
7565
7566 trace("Message sequences by WM_IME_KEYDOWN\n");
7567
7568 register_wmime_keydown_class();
7569 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7570 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7571 NULL, NULL, 0);
7572 flush_events();
7573 flush_sequence();
7574
7575 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7576 SendMessageA(hwnd, WM_CHAR, 'A', 1);
7577 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7578
7579 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7580 {
7581 TranslateMessage(&msg);
7582 DispatchMessageA(&msg);
7583 }
7584 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7585
7586 DestroyWindow(hwnd);
7587 }
7588
7589 /************* painting message test ********************/
7590
7591 void dump_region(HRGN hrgn)
7592 {
7593 DWORD i, size;
7594 RGNDATA *data = NULL;
7595 RECT *rect;
7596
7597 if (!hrgn)
7598 {
7599 printf( "null region\n" );
7600 return;
7601 }
7602 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7603 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7604 GetRegionData( hrgn, size, data );
7605 printf("%d rects:", data->rdh.nCount );
7606 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7607 printf( " %s", wine_dbgstr_rect( rect ));
7608 printf("\n");
7609 HeapFree( GetProcessHeap(), 0, data );
7610 }
7611
7612 static void check_update_rgn( HWND hwnd, HRGN hrgn )
7613 {
7614 INT ret;
7615 RECT r1, r2;
7616 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7617 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7618
7619 ret = GetUpdateRgn( hwnd, update, FALSE );
7620 ok( ret != ERROR, "GetUpdateRgn failed\n" );
7621 if (ret == NULLREGION)
7622 {
7623 ok( !hrgn, "Update region shouldn't be empty\n" );
7624 }
7625 else
7626 {
7627 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7628 {
7629 ok( 0, "Regions are different\n" );
7630 if (winetest_debug > 0)
7631 {
7632 printf( "Update region: " );
7633 dump_region( update );
7634 printf( "Wanted region: " );
7635 dump_region( hrgn );
7636 }
7637 }
7638 }
7639 GetRgnBox( update, &r1 );
7640 GetUpdateRect( hwnd, &r2, FALSE );
7641 ok( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", wine_dbgstr_rect( &r1 ),
7642 wine_dbgstr_rect( &r2 ));
7643
7644 DeleteObject( tmp );
7645 DeleteObject( update );
7646 }
7647
7648 static const struct message WmInvalidateRgn[] = {
7649 { WM_NCPAINT, sent },
7650 { WM_GETTEXT, sent|defwinproc|optional },
7651 { 0 }
7652 };
7653
7654 static const struct message WmGetUpdateRect[] = {
7655 { WM_NCPAINT, sent },
7656 { WM_GETTEXT, sent|defwinproc|optional },
7657 { WM_PAINT, sent },
7658 { 0 }
7659 };
7660
7661 static const struct message WmInvalidateFull[] = {
7662 { WM_NCPAINT, sent|wparam, 1 },
7663 { WM_GETTEXT, sent|defwinproc|optional },
7664 { 0 }
7665 };
7666
7667 static const struct message WmInvalidateErase[] = {
7668 { WM_NCPAINT, sent|wparam, 1 },
7669 { WM_GETTEXT, sent|defwinproc|optional },
7670 { WM_ERASEBKGND, sent },
7671 { 0 }
7672 };
7673
7674 static const struct message WmInvalidatePaint[] = {
7675 { WM_PAINT, sent },
7676 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7677 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7678 { 0 }
7679 };
7680
7681 static const struct message WmInvalidateErasePaint[] = {
7682 { WM_PAINT, sent },
7683 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7684 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7685 { WM_ERASEBKGND, sent|beginpaint|optional },
7686 { 0 }
7687 };
7688
7689 static const struct message WmInvalidateErasePaint2[] = {
7690 { WM_PAINT, sent },
7691 { WM_NCPAINT, sent|beginpaint },
7692 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7693 { WM_ERASEBKGND, sent|beginpaint|optional },
7694 { 0 }
7695 };
7696
7697 static const struct message WmErase[] = {
7698 { WM_ERASEBKGND, sent },
7699 { 0 }
7700 };
7701
7702 static const struct message WmPaint[] = {
7703 { WM_PAINT, sent },
7704 { 0 }
7705 };
7706
7707 static const struct message WmParentOnlyPaint[] = {
7708 { WM_PAINT, sent|parent },
7709 { 0 }
7710 };
7711
7712 static const struct message WmInvalidateParent[] = {
7713 { WM_NCPAINT, sent|parent },
7714 { WM_GETTEXT, sent|defwinproc|parent|optional },
7715 { WM_ERASEBKGND, sent|parent },
7716 { 0 }
7717 };
7718
7719 static const struct message WmInvalidateParentChild[] = {
7720 { WM_NCPAINT, sent|parent },
7721 { WM_GETTEXT, sent|defwinproc|parent|optional },
7722 { WM_ERASEBKGND, sent|parent },
7723 { WM_NCPAINT, sent },
7724 { WM_GETTEXT, sent|defwinproc|optional },
7725 { WM_ERASEBKGND, sent },
7726 { 0 }
7727 };
7728
7729 static const struct message WmInvalidateParentChild2[] = {
7730 { WM_ERASEBKGND, sent|parent },
7731 { WM_NCPAINT, sent },
7732 { WM_GETTEXT, sent|defwinproc|optional },
7733 { WM_ERASEBKGND, sent },
7734 { 0 }
7735 };
7736
7737 static const struct message WmParentPaint[] = {
7738 { WM_PAINT, sent|parent },
7739 { WM_PAINT, sent },
7740 { 0 }
7741 };
7742
7743 static const struct message WmParentPaintNc[] = {
7744 { WM_PAINT, sent|parent },
7745 { WM_PAINT, sent },
7746 { WM_NCPAINT, sent|beginpaint },
7747 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7748 { WM_ERASEBKGND, sent|beginpaint|optional },
7749 { 0 }
7750 };
7751
7752 static const struct message WmChildPaintNc[] = {
7753 { WM_PAINT, sent },
7754 { WM_NCPAINT, sent|beginpaint },
7755 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7756 { WM_ERASEBKGND, sent|beginpaint|optional },
7757 { 0 }
7758 };
7759
7760 static const struct message WmParentErasePaint[] = {
7761 { WM_PAINT, sent|parent },
7762 { WM_NCPAINT, sent|parent|beginpaint },
7763 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7764 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7765 { WM_PAINT, sent },
7766 { WM_NCPAINT, sent|beginpaint },
7767 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7768 { WM_ERASEBKGND, sent|beginpaint|optional },
7769 { 0 }
7770 };
7771
7772 static const struct message WmParentOnlyNcPaint[] = {
7773 { WM_PAINT, sent|parent },
7774 { WM_NCPAINT, sent|parent|beginpaint },
7775 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7776 { 0 }
7777 };
7778
7779 static const struct message WmSetParentStyle[] = {
7780 { WM_STYLECHANGING, sent|parent },
7781 { WM_STYLECHANGED, sent|parent },
7782 { 0 }
7783 };
7784
7785 static void test_paint_messages(void)
7786 {
7787 BOOL ret;
7788 RECT rect, rect2;
7789 POINT pt;
7790 MSG msg;
7791 HWND hparent, hchild;
7792 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7793 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7794 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7795 100, 100, 200, 200, 0, 0, 0, NULL);
7796 ok (hwnd != 0, "Failed to create overlapped window\n");
7797
7798 ShowWindow( hwnd, SW_SHOW );
7799 UpdateWindow( hwnd );
7800 flush_events();
7801 flush_sequence();
7802
7803 check_update_rgn( hwnd, 0 );
7804 SetRectRgn( hrgn, 10, 10, 20, 20 );
7805 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7806 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7807 check_update_rgn( hwnd, hrgn );
7808 SetRectRgn( hrgn2, 20, 20, 30, 30 );
7809 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7810 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7811 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7812 check_update_rgn( hwnd, hrgn );
7813 /* validate everything */
7814 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7815 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7816 check_update_rgn( hwnd, 0 );
7817
7818 /* test empty region */
7819 SetRectRgn( hrgn, 10, 10, 10, 15 );
7820 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7821 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7822 check_update_rgn( hwnd, 0 );
7823 /* test empty rect */
7824 SetRect( &rect, 10, 10, 10, 15 );
7825 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7826 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7827 check_update_rgn( hwnd, 0 );
7828
7829 /* flush pending messages */
7830 flush_events();
7831 flush_sequence();
7832
7833 GetClientRect( hwnd, &rect );
7834 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7835 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7836 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7837 */
7838 trace("testing InvalidateRect(0, NULL, FALSE)\n");
7839 SetRectEmpty( &rect );
7840 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
7841 check_update_rgn( hwnd, hrgn );
7842 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7843 flush_events();
7844 ok_sequence( WmPaint, "Paint", FALSE );
7845 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7846 check_update_rgn( hwnd, 0 );
7847
7848 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
7849 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7850 */
7851 trace("testing ValidateRect(0, NULL)\n");
7852 SetRectEmpty( &rect );
7853 if (ValidateRect(0, &rect) && /* not supported on Win9x */
7854 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
7855 {
7856 check_update_rgn( hwnd, hrgn );
7857 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7858 flush_events();
7859 ok_sequence( WmPaint, "Paint", FALSE );
7860 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7861 check_update_rgn( hwnd, 0 );
7862 }
7863
7864 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
7865 SetLastError(0xdeadbeef);
7866 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
7867 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
7868 "wrong error code %d\n", GetLastError());
7869 check_update_rgn( hwnd, 0 );
7870 flush_events();
7871 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7872
7873 trace("testing ValidateRgn(0, NULL)\n");
7874 SetLastError(0xdeadbeef);
7875 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
7876 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7877 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7878 "wrong error code %d\n", GetLastError());
7879 check_update_rgn( hwnd, 0 );
7880 flush_events();
7881 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7882
7883 trace("testing UpdateWindow(NULL)\n");
7884 SetLastError(0xdeadbeef);
7885 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
7886 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7887 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7888 "wrong error code %d\n", GetLastError());
7889 check_update_rgn( hwnd, 0 );
7890 flush_events();
7891 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7892
7893 /* now with frame */
7894 SetRectRgn( hrgn, -5, -5, 20, 20 );
7895
7896 /* flush pending messages */
7897 flush_events();
7898 flush_sequence();
7899 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7900 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7901
7902 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
7903 check_update_rgn( hwnd, hrgn );
7904
7905 flush_sequence();
7906 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7907 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7908
7909 flush_sequence();
7910 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7911 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
7912
7913 GetClientRect( hwnd, &rect );
7914 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7915 check_update_rgn( hwnd, hrgn );
7916
7917 flush_sequence();
7918 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
7919 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7920
7921 flush_sequence();
7922 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
7923 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
7924 check_update_rgn( hwnd, 0 );
7925
7926 flush_sequence();
7927 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
7928 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
7929 check_update_rgn( hwnd, 0 );
7930
7931 flush_sequence();
7932 SetRectRgn( hrgn, 0, 0, 100, 100 );
7933 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7934 SetRectRgn( hrgn, 0, 0, 50, 100 );
7935 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
7936 SetRectRgn( hrgn, 50, 0, 100, 100 );
7937 check_update_rgn( hwnd, hrgn );
7938 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7939 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
7940 check_update_rgn( hwnd, 0 );
7941
7942 flush_sequence();
7943 SetRectRgn( hrgn, 0, 0, 100, 100 );
7944 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7945 SetRectRgn( hrgn, 0, 0, 100, 50 );
7946 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7947 ok_sequence( WmErase, "Erase", FALSE );
7948 SetRectRgn( hrgn, 0, 50, 100, 100 );
7949 check_update_rgn( hwnd, hrgn );
7950
7951 flush_sequence();
7952 SetRectRgn( hrgn, 0, 0, 100, 100 );
7953 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7954 SetRectRgn( hrgn, 0, 0, 50, 50 );
7955 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
7956 ok_sequence( WmPaint, "Paint", FALSE );
7957
7958 flush_sequence();
7959 SetRectRgn( hrgn, -4, -4, -2, -2 );
7960 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7961 SetRectRgn( hrgn, -200, -200, -198, -198 );
7962 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
7963 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7964
7965 flush_sequence();
7966 SetRectRgn( hrgn, -4, -4, -2, -2 );
7967 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7968 SetRectRgn( hrgn, -4, -4, -3, -3 );
7969 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
7970 SetRectRgn( hrgn, 0, 0, 1, 1 );
7971 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
7972 ok_sequence( WmPaint, "Paint", FALSE );
7973
7974 flush_sequence();
7975 SetRectRgn( hrgn, -4, -4, -1, -1 );
7976 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7977 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
7978 /* make sure no WM_PAINT was generated */
7979 flush_events();
7980 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7981
7982 flush_sequence();
7983 SetRectRgn( hrgn, -4, -4, -1, -1 );
7984 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7985 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
7986 {
7987 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
7988 {
7989 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
7990 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
7991 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
7992 ret = GetUpdateRect( hwnd, &rect, FALSE );
7993 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
7994 /* this will send WM_NCPAINT and validate the non client area */
7995 ret = GetUpdateRect( hwnd, &rect, TRUE );
7996 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
7997 }
7998 DispatchMessageA( &msg );
7999 }
8000 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8001
8002 DestroyWindow( hwnd );
8003
8004 /* now test with a child window */
8005
8006 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8007 100, 100, 200, 200, 0, 0, 0, NULL);
8008 ok (hparent != 0, "Failed to create parent window\n");
8009
8010 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8011 10, 10, 100, 100, hparent, 0, 0, NULL);
8012 ok (hchild != 0, "Failed to create child window\n");
8013
8014 ShowWindow( hparent, SW_SHOW );
8015 UpdateWindow( hparent );
8016 UpdateWindow( hchild );
8017 flush_events();
8018 flush_sequence();
8019 log_all_parent_messages++;
8020
8021 SetRect( &rect, 0, 0, 50, 50 );
8022 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8023 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8024 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8025
8026 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8027 pt.x = pt.y = 0;
8028 MapWindowPoints( hchild, hparent, &pt, 1 );
8029 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8030 check_update_rgn( hchild, hrgn );
8031 SetRectRgn( hrgn, 0, 0, 50, 50 );
8032 check_update_rgn( hparent, hrgn );
8033 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8034 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8035 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8036 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8037
8038 flush_events();
8039 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8040
8041 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8042 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8043 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8044 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8045 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8046
8047 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8048 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8049 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8050
8051 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8052 flush_sequence();
8053 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8054 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8055 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8056
8057 /* flush all paint messages */
8058 flush_events();
8059 flush_sequence();
8060
8061 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8062 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8063 SetRectRgn( hrgn, 0, 0, 50, 50 );
8064 check_update_rgn( hparent, hrgn );
8065 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8066 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8067 SetRectRgn( hrgn, 0, 0, 50, 50 );
8068 check_update_rgn( hparent, hrgn );
8069
8070 /* flush all paint messages */
8071 flush_events();
8072 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8073 flush_sequence();
8074
8075 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8076 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8077 SetRectRgn( hrgn, 0, 0, 50, 50 );
8078 check_update_rgn( hparent, hrgn );
8079 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8080 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8081 SetRectRgn( hrgn2, 10, 10, 50, 50 );
8082 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8083 check_update_rgn( hparent, hrgn );
8084 /* flush all paint messages */
8085 flush_events();
8086 flush_sequence();
8087
8088 /* same as above but parent gets completely validated */
8089 SetRect( &rect, 20, 20, 30, 30 );
8090 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8091 SetRectRgn( hrgn, 20, 20, 30, 30 );
8092 check_update_rgn( hparent, hrgn );
8093 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8094 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8095 check_update_rgn( hparent, 0 ); /* no update region */
8096 flush_events();
8097 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
8098
8099 /* make sure RDW_VALIDATE on child doesn't have the same effect */
8100 flush_sequence();
8101 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8102 SetRectRgn( hrgn, 20, 20, 30, 30 );
8103 check_update_rgn( hparent, hrgn );
8104 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8105 SetRectRgn( hrgn, 20, 20, 30, 30 );
8106 check_update_rgn( hparent, hrgn );
8107
8108 /* same as above but normal WM_PAINT doesn't validate parent */
8109 flush_sequence();
8110 SetRect( &rect, 20, 20, 30, 30 );
8111 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8112 SetRectRgn( hrgn, 20, 20, 30, 30 );
8113 check_update_rgn( hparent, hrgn );
8114 /* no WM_PAINT in child while parent still pending */
8115 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8116 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8117 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8118 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8119
8120 flush_sequence();
8121 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8122 /* no WM_PAINT in child while parent still pending */
8123 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8124 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8125 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8126 /* now that parent is valid child should get WM_PAINT */
8127 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8128 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8129 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8130 ok_sequence( WmEmptySeq, "No other message", FALSE );
8131
8132 /* same thing with WS_CLIPCHILDREN in parent */
8133 flush_sequence();
8134 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8135 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8136 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8137 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8138 ok_sequence( WmEmptySeq, "No message", FALSE );
8139 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8140 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8141
8142 flush_sequence();
8143 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8144 SetRectRgn( hrgn, 20, 20, 30, 30 );
8145 check_update_rgn( hparent, hrgn );
8146 /* no WM_PAINT in child while parent still pending */
8147 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8148 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8149 /* WM_PAINT in parent first */
8150 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8151 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8152
8153 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8154 flush_sequence();
8155 SetRect( &rect, 0, 0, 30, 30 );
8156 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8157 SetRectRgn( hrgn, 0, 0, 30, 30 );
8158 check_update_rgn( hparent, hrgn );
8159 flush_events();
8160 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8161
8162 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8163 flush_sequence();
8164 SetRect( &rect, -10, 0, 30, 30 );
8165 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8166 SetRect( &rect, 0, 0, 20, 20 );
8167 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8168 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8169 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8170
8171 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8172 flush_sequence();
8173 SetRect( &rect, -10, 0, 30, 30 );
8174 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8175 SetRect( &rect, 0, 0, 100, 100 );
8176 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8177 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8178 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8179 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8180 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8181
8182 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8183 flush_sequence();
8184 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8185 GetClientRect( hparent, &rect );
8186 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8187 check_update_rgn( hparent, hrgn );
8188 flush_events();
8189
8190 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8191 GetClientRect( hparent, &rect );
8192 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8193 check_update_rgn( hparent, hrgn );
8194 flush_events();
8195
8196 /* test RDW_INTERNALPAINT behavior */
8197
8198 flush_sequence();
8199 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8200 flush_events();
8201 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8202
8203 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8204 flush_events();
8205 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8206
8207 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8208 flush_events();
8209 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8210
8211 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8212 UpdateWindow( hparent );
8213 flush_events();
8214 flush_sequence();
8215 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8216 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8217 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8218 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8219 flush_events();
8220 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8221
8222 UpdateWindow( hparent );
8223 flush_events();
8224 flush_sequence();
8225 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8226 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8227 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8228 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8229 flush_events();
8230 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8231
8232 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8233 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8234 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8235 flush_events();
8236 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8237
8238 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8239 UpdateWindow( hparent );
8240 flush_events();
8241 flush_sequence();
8242 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8243 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8244 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8245 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8246 flush_events();
8247 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8248
8249 UpdateWindow( hparent );
8250 flush_events();
8251 flush_sequence();
8252 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8253 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8254 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8255 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8256 flush_events();
8257 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8258
8259 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8260 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8261
8262 UpdateWindow( hparent );
8263 flush_events();
8264 flush_sequence();
8265 trace("testing SetWindowPos(-10000, -10000) on child\n");
8266 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8267 check_update_rgn( hchild, 0 );
8268 flush_events();
8269
8270 #if 0 /* this one doesn't pass under Wine yet */
8271 UpdateWindow( hparent );
8272 flush_events();
8273 flush_sequence();
8274 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8275 ShowWindow( hchild, SW_MINIMIZE );
8276 check_update_rgn( hchild, 0 );
8277 flush_events();
8278 #endif
8279
8280 UpdateWindow( hparent );
8281 flush_events();
8282 flush_sequence();
8283 trace("testing SetWindowPos(-10000, -10000) on parent\n");
8284 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8285 check_update_rgn( hparent, 0 );
8286 flush_events();
8287
8288 log_all_parent_messages--;
8289 DestroyWindow( hparent );
8290 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8291
8292 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8293
8294 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8295 100, 100, 200, 200, 0, 0, 0, NULL);
8296 ok (hparent != 0, "Failed to create parent window\n");
8297
8298 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8299 10, 10, 100, 100, hparent, 0, 0, NULL);
8300 ok (hchild != 0, "Failed to create child window\n");
8301
8302 ShowWindow( hparent, SW_SHOW );
8303 UpdateWindow( hparent );
8304 UpdateWindow( hchild );
8305 flush_events();
8306 flush_sequence();
8307
8308 /* moving child outside of parent boundaries changes update region */
8309 SetRect( &rect, 0, 0, 40, 40 );
8310 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8311 SetRectRgn( hrgn, 0, 0, 40, 40 );
8312 check_update_rgn( hchild, hrgn );
8313 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8314 SetRectRgn( hrgn, 10, 0, 40, 40 );
8315 check_update_rgn( hchild, hrgn );
8316 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8317 SetRectRgn( hrgn, 10, 10, 40, 40 );
8318 check_update_rgn( hchild, hrgn );
8319
8320 /* moving parent off-screen does too */
8321 SetRect( &rect, 0, 0, 100, 100 );
8322 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8323 SetRectRgn( hrgn, 0, 0, 100, 100 );
8324 check_update_rgn( hparent, hrgn );
8325 SetRectRgn( hrgn, 10, 10, 40, 40 );
8326 check_update_rgn( hchild, hrgn );
8327 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8328 GetUpdateRect( hparent, &rect2, FALSE );
8329 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8330 {
8331 rect.left += 20;
8332 rect.top += 20;
8333 }
8334 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8335 check_update_rgn( hparent, hrgn );
8336 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8337 check_update_rgn( hchild, hrgn );
8338
8339 /* invalidated region is cropped by the parent rects */
8340 SetRect( &rect, 0, 0, 50, 50 );
8341 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8342 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8343 check_update_rgn( hchild, hrgn );
8344
8345 DestroyWindow( hparent );
8346 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8347 flush_sequence();
8348
8349 DeleteObject( hrgn );
8350 DeleteObject( hrgn2 );
8351 }
8352
8353 struct wnd_event
8354 {
8355 HWND hwnd;
8356 HANDLE grand_child;
8357 HANDLE start_event;
8358 HANDLE stop_event;
8359 };
8360
8361 static DWORD WINAPI thread_proc(void *param)
8362 {
8363 MSG msg;
8364 struct wnd_event *wnd_event = param;
8365
8366 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8367 100, 100, 200, 200, 0, 0, 0, NULL);
8368 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8369
8370 SetEvent(wnd_event->start_event);
8371
8372 while (GetMessageA(&msg, 0, 0, 0))
8373 {
8374 TranslateMessage(&msg);
8375 DispatchMessageA(&msg);
8376 }
8377
8378 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8379
8380 return 0;
8381 }
8382
8383 static DWORD CALLBACK create_grand_child_thread( void *param )
8384 {
8385 struct wnd_event *wnd_event = param;
8386 HWND hchild;
8387 MSG msg;
8388
8389 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8390 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8391 ok (hchild != 0, "Failed to create child window\n");
8392 flush_events();
8393 flush_sequence();
8394 SetEvent( wnd_event->start_event );
8395
8396 for (;;)
8397 {
8398 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8399 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
8400 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8401 }
8402 return 0;
8403 }
8404
8405 static DWORD CALLBACK create_child_thread( void *param )
8406 {
8407 struct wnd_event *wnd_event = param;
8408 struct wnd_event child_event;
8409 DWORD ret, tid;
8410 MSG msg;
8411
8412 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8413 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8414 ok (child_event.hwnd != 0, "Failed to create child window\n");
8415 SetFocus( child_event.hwnd );
8416 flush_events();
8417 flush_sequence();
8418 child_event.start_event = wnd_event->start_event;
8419 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8420 for (;;)
8421 {
8422 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8423 if (ret != 1) break;
8424 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8425 }
8426 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8427 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8428 return 0;
8429 }
8430
8431 static const char manifest_dep[] =
8432 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8433 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8434 " <file name=\"testdep.dll\" />"
8435 "</assembly>";
8436
8437 static const char manifest_main[] =
8438 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8439 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8440 "<dependency>"
8441 " <dependentAssembly>"
8442 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8443 " </dependentAssembly>"
8444 "</dependency>"
8445 "</assembly>";
8446
8447 static void create_manifest_file(const char *filename, const char *manifest)
8448 {
8449 WCHAR path[MAX_PATH];
8450 HANDLE file;
8451 DWORD size;
8452
8453 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8454 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8455 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8456 WriteFile(file, manifest, strlen(manifest), &size, NULL);
8457 CloseHandle(file);
8458 }
8459
8460 static HANDLE test_create(const char *file)
8461 {
8462 WCHAR path[MAX_PATH];
8463 ACTCTXW actctx;
8464 HANDLE handle;
8465
8466 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8467 memset(&actctx, 0, sizeof(ACTCTXW));
8468 actctx.cbSize = sizeof(ACTCTXW);
8469 actctx.lpSource = path;
8470
8471 handle = pCreateActCtxW(&actctx);
8472 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8473
8474 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8475 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8476 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8477 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8478 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8479 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8480 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8481 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8482 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8483
8484 return handle;
8485 }
8486
8487 static void test_interthread_messages(void)
8488 {
8489 HANDLE hThread, context, handle, event;
8490 ULONG_PTR cookie;
8491 DWORD tid;
8492 WNDPROC proc;
8493 MSG msg;
8494 char buf[256];
8495 int len, expected_len;
8496 struct wnd_event wnd_event;
8497 BOOL ret;
8498
8499 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8500 if (!wnd_event.start_event)
8501 {
8502 win_skip("skipping interthread message test under win9x\n");
8503 return;
8504 }
8505
8506 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8507 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8508
8509 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8510
8511 CloseHandle(wnd_event.start_event);
8512
8513 SetLastError(0xdeadbeef);
8514 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8515 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8516 "wrong error code %d\n", GetLastError());
8517
8518 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8519 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8520
8521 expected_len = lstrlenA("window caption text");
8522 memset(buf, 0, sizeof(buf));
8523 SetLastError(0xdeadbeef);
8524 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8525 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8526 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8527
8528 msg.hwnd = wnd_event.hwnd;
8529 msg.message = WM_GETTEXT;
8530 msg.wParam = sizeof(buf);
8531 msg.lParam = (LPARAM)buf;
8532 memset(buf, 0, sizeof(buf));
8533 SetLastError(0xdeadbeef);
8534 len = DispatchMessageA(&msg);
8535 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8536 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8537
8538 /* the following test causes an exception in user.exe under win9x */
8539 msg.hwnd = wnd_event.hwnd;
8540 msg.message = WM_TIMER;
8541 msg.wParam = 0;
8542 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8543 SetLastError(0xdeadbeef);
8544 len = DispatchMessageA(&msg);
8545 ok(!len && GetLastError() == 0xdeadbeef,
8546 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8547
8548 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8549 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8550
8551 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8552 CloseHandle(hThread);
8553
8554 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8555
8556 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8557 100, 100, 200, 200, 0, 0, 0, NULL);
8558 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8559 flush_events();
8560 flush_sequence();
8561 log_all_parent_messages++;
8562 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8563 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8564 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
8565 for (;;)
8566 {
8567 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8568 if (ret != 1) break;
8569 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8570 }
8571 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
8572 /* now wait for the thread without processing messages; this shouldn't deadlock */
8573 SetEvent( wnd_event.stop_event );
8574 ret = WaitForSingleObject( hThread, 5000 );
8575 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8576 CloseHandle( hThread );
8577
8578 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8579 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8580 CloseHandle( wnd_event.grand_child );
8581
8582 CloseHandle( wnd_event.start_event );
8583 CloseHandle( wnd_event.stop_event );
8584 flush_events();
8585 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8586 log_all_parent_messages--;
8587 DestroyWindow( wnd_event.hwnd );
8588
8589 /* activation context tests */
8590 if (!pActivateActCtx)
8591 {
8592 win_skip("Activation contexts are not supported, skipping\n");
8593 return;
8594 }
8595
8596 create_manifest_file("testdep1.manifest", manifest_dep);
8597 create_manifest_file("main.manifest", manifest_main);
8598
8599 context = test_create("main.manifest");
8600 DeleteFileA("testdep1.manifest");
8601 DeleteFileA("main.manifest");
8602
8603 handle = (void*)0xdeadbeef;
8604 ret = pGetCurrentActCtx(&handle);
8605 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8606 ok(handle == 0, "active context %p\n", handle);
8607
8608 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8609 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8610 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8611 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8612 CloseHandle(wnd_event.start_event);
8613
8614 /* context is activated after thread creation, so it doesn't inherit it by default */
8615 ret = pActivateActCtx(context, &cookie);
8616 ok(ret, "activation failed: %u\n", GetLastError());
8617
8618 handle = 0;
8619 ret = pGetCurrentActCtx(&handle);
8620 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8621 ok(handle != 0, "active context %p\n", handle);
8622 pReleaseActCtx(handle);
8623
8624 /* destination window will test for active context */
8625 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8626 ok(ret, "thread window returned %d\n", ret);
8627
8628 event = CreateEventW(NULL, 0, 0, NULL);
8629 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8630 ok(ret, "thread window returned %d\n", ret);
8631 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8632 CloseHandle(event);
8633
8634 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8635 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8636
8637 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8638 CloseHandle(hThread);
8639
8640 ret = pDeactivateActCtx(0, cookie);
8641 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8642 pReleaseActCtx(context);
8643 }
8644
8645
8646 static const struct message WmVkN[] = {
8647 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8648 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8649 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8650 { WM_CHAR, wparam|lparam, 'n', 1 },
8651 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8652 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8653 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8654 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8655 { 0 }
8656 };
8657 static const struct message WmShiftVkN[] = {
8658 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8659 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8660 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8661 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8662 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8663 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8664 { WM_CHAR, wparam|lparam, 'N', 1 },
8665 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8666 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8667 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8668 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8669 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8670 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8671 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8672 { 0 }
8673 };
8674 static const struct message WmCtrlVkN[] = {
8675 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8676 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8677 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8678 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8679 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8680 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8681 { WM_CHAR, wparam|lparam, 0x000e, 1 },
8682 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8683 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8684 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8685 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8686 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8687 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8688 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8689 { 0 }
8690 };
8691 static const struct message WmCtrlVkN_2[] = {
8692 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8693 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8694 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8695 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8696 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8697 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8698 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8699 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8700 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8701 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8702 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8703 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8704 { 0 }
8705 };
8706 static const struct message WmAltVkN[] = {
8707 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8708 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8709 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8710 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8711 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8712 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8713 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8714 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8715 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8716 { HCBT_SYSCOMMAND, hook },
8717 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8718 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8719 { 0x00AE, sent|defwinproc|optional }, /* XP */
8720 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8721 { WM_INITMENU, sent|defwinproc },
8722 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8723 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8724 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8725 { WM_CAPTURECHANGED, sent|defwinproc },
8726 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8727 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8728 { WM_EXITMENULOOP, sent|defwinproc },
8729 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8730 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8731 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8732 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8733 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8734 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8735 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8736 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8737 { 0 }
8738 };
8739 static const struct message WmAltVkN_2[] = {
8740 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8741 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8742 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8743 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8744 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8745 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8746 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8747 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8748 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8749 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8750 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8751 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8752 { 0 }
8753 };
8754 static const struct message WmCtrlAltVkN[] = {
8755 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8756 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8757 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8758 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8759 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8760 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8761 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8762 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8763 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8764 { WM_CHAR, optional },
8765 { WM_CHAR, sent|optional },
8766 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8767 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8768 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8769 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8770 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8771 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8772 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8773 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8774 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8775 { 0 }
8776 };
8777 static const struct message WmCtrlShiftVkN[] = {
8778 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8779 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8780 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8781 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8782 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8783 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8784 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8785 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8786 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8787 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8788 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8789 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8790 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8791 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8792 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8793 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8794 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8795 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8796 { 0 }
8797 };
8798 static const struct message WmCtrlAltShiftVkN[] = {
8799 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8800 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8801 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8802 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8803 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8804 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8805 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8806 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8807 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8808 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8809 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8810 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8811 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8812 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8813 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8814 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8815 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8816 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8817 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8818 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8819 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8820 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8821 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8822 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8823 { 0 }
8824 };
8825 static const struct message WmAltPressRelease[] = {
8826 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8827 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8828 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8829 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8830 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8831 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8832 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
8833 { HCBT_SYSCOMMAND, hook },
8834 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8835 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8836 { WM_INITMENU, sent|defwinproc },
8837 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8838 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8839 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8840
8841 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
8842
8843 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8844 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8845 { WM_CAPTURECHANGED, sent|defwinproc },
8846 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8847 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8848 { WM_EXITMENULOOP, sent|defwinproc },
8849 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8850 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8851 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8852 { 0 }
8853 };
8854 static const struct message WmShiftMouseButton[] = {
8855 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8856 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8857 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8858 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
8859 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
8860 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
8861 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
8862 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
8863 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
8864 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8865 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8866 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8867 { 0 }
8868 };
8869 static const struct message WmF1Seq[] = {
8870 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
8871 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
8872 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
8873 { WM_KEYF1, wparam|lparam, 0, 0 },
8874 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
8875 { WM_HELP, sent|defwinproc },
8876 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
8877 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
8878 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
8879 { 0 }
8880 };
8881 static const struct message WmVkAppsSeq[] = {
8882 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
8883 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
8884 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
8885 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
8886 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
8887 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
8888 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
8889 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
8890 { 0 }
8891 };
8892 static const struct message WmVkF10Seq[] = {
8893 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8894 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8895 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8896 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8897 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8898 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8899 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8900 { HCBT_SYSCOMMAND, hook },
8901 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8902 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8903 { WM_INITMENU, sent|defwinproc },
8904 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8905 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8906 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8907
8908 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
8909
8910 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8911 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8912 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8913 { WM_CAPTURECHANGED, sent|defwinproc },
8914 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8915 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8916 { WM_EXITMENULOOP, sent|defwinproc },
8917 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8918 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8919 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8920 { 0 }
8921 };
8922 static const struct message WmShiftF10Seq[] = {
8923 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8924 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8925 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
8926 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8927 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8928 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8929 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
8930 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8931 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8932 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8933 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8934 { HCBT_SYSCOMMAND, hook },
8935 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8936 { WM_INITMENU, sent|defwinproc },
8937 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8938 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
8939 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
8940 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
8941 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
8942 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8943 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
8944 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
8945 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
8946 { 0 }
8947 };
8948
8949 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
8950 {
8951 MSG msg;
8952
8953 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
8954 {
8955 struct recvd_message log_msg;
8956
8957 /* ignore some unwanted messages */
8958 if (msg.message == WM_MOUSEMOVE ||
8959 msg.message == WM_TIMER ||
8960 ignore_message( msg.message ))
8961 continue;
8962
8963 log_msg.hwnd = msg.hwnd;
8964 log_msg.message = msg.message;
8965 log_msg.flags = wparam|lparam;
8966 log_msg.wParam = msg.wParam;
8967 log_msg.lParam = msg.lParam;
8968 log_msg.descr = "accel";
8969 add_message(&log_msg);
8970
8971 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
8972 {
8973 TranslateMessage(&msg);
8974 DispatchMessageA(&msg);
8975 }
8976 }
8977 }
8978
8979 static void test_accelerators(void)
8980 {
8981 RECT rc;
8982 POINT pt;
8983 SHORT state;
8984 HACCEL hAccel;
8985 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8986 100, 100, 200, 200, 0, 0, 0, NULL);
8987 BOOL ret;
8988
8989 assert(hwnd != 0);
8990 UpdateWindow(hwnd);
8991 flush_events();
8992 flush_sequence();
8993
8994 SetFocus(hwnd);
8995 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
8996
8997 state = GetKeyState(VK_SHIFT);
8998 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
8999 state = GetKeyState(VK_CAPITAL);
9000 ok(state == 0, "wrong CapsLock state %04x\n", state);
9001
9002 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
9003 assert(hAccel != 0);
9004
9005 flush_events();
9006 pump_msg_loop(hwnd, 0);
9007 flush_sequence();
9008
9009 trace("testing VK_N press/release\n");
9010 flush_sequence();
9011 keybd_event('N', 0, 0, 0);
9012 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9013 pump_msg_loop(hwnd, hAccel);
9014 if (!sequence_cnt) /* we didn't get any message */
9015 {
9016 skip( "queuing key events not supported\n" );
9017 goto done;
9018 }
9019 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9020
9021 trace("testing Shift+VK_N press/release\n");
9022 flush_sequence();
9023 keybd_event(VK_SHIFT, 0, 0, 0);
9024 keybd_event('N', 0, 0, 0);
9025 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9026 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9027 pump_msg_loop(hwnd, hAccel);
9028 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9029
9030 trace("testing Ctrl+VK_N press/release\n");
9031 flush_sequence();
9032 keybd_event(VK_CONTROL, 0, 0, 0);
9033 keybd_event('N', 0, 0, 0);
9034 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9035 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9036 pump_msg_loop(hwnd, hAccel);
9037 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
9038
9039 trace("testing Alt+VK_N press/release\n");
9040 flush_sequence();
9041 keybd_event(VK_MENU, 0, 0, 0);
9042 keybd_event('N', 0, 0, 0);
9043 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9044 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9045 pump_msg_loop(hwnd, hAccel);
9046 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
9047
9048 trace("testing Ctrl+Alt+VK_N press/release 1\n");
9049 flush_sequence();
9050 keybd_event(VK_CONTROL, 0, 0, 0);
9051 keybd_event(VK_MENU, 0, 0, 0);
9052 keybd_event('N', 0, 0, 0);
9053 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9054 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9055 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9056 pump_msg_loop(hwnd, hAccel);
9057 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
9058
9059 ret = DestroyAcceleratorTable(hAccel);
9060 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9061
9062 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
9063 assert(hAccel != 0);
9064
9065 trace("testing VK_N press/release\n");
9066 flush_sequence();
9067 keybd_event('N', 0, 0, 0);
9068 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9069 pump_msg_loop(hwnd, hAccel);
9070 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9071
9072 trace("testing Shift+VK_N press/release\n");
9073 flush_sequence();
9074 keybd_event(VK_SHIFT, 0, 0, 0);
9075 keybd_event('N', 0, 0, 0);
9076 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9077 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9078 pump_msg_loop(hwnd, hAccel);
9079 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9080
9081 trace("testing Ctrl+VK_N press/release 2\n");
9082 flush_sequence();
9083 keybd_event(VK_CONTROL, 0, 0, 0);
9084 keybd_event('N', 0, 0, 0);
9085 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9086 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9087 pump_msg_loop(hwnd, hAccel);
9088 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
9089
9090 trace("testing Alt+VK_N press/release 2\n");
9091 flush_sequence();
9092 keybd_event(VK_MENU, 0, 0, 0);
9093 keybd_event('N', 0, 0, 0);
9094 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9095 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9096 pump_msg_loop(hwnd, hAccel);
9097 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
9098
9099 trace("testing Ctrl+Alt+VK_N press/release 2\n");
9100 flush_sequence();
9101 keybd_event(VK_CONTROL, 0, 0, 0);
9102 keybd_event(VK_MENU, 0, 0, 0);
9103 keybd_event('N', 0, 0, 0);
9104 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9105 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9106 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9107 pump_msg_loop(hwnd, hAccel);
9108 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9109
9110 trace("testing Ctrl+Shift+VK_N press/release\n");
9111 flush_sequence();
9112 keybd_event(VK_CONTROL, 0, 0, 0);
9113 keybd_event(VK_SHIFT, 0, 0, 0);
9114 keybd_event('N', 0, 0, 0);
9115 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9116 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9117 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9118 pump_msg_loop(hwnd, hAccel);
9119 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9120
9121 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9122 flush_sequence();
9123 keybd_event(VK_CONTROL, 0, 0, 0);
9124 keybd_event(VK_MENU, 0, 0, 0);
9125 keybd_event(VK_SHIFT, 0, 0, 0);
9126 keybd_event('N', 0, 0, 0);
9127 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9128 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9129 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9130 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9131 pump_msg_loop(hwnd, hAccel);
9132 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9133
9134 ret = DestroyAcceleratorTable(hAccel);
9135 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9136 hAccel = 0;
9137
9138 trace("testing Alt press/release\n");
9139 flush_sequence();
9140 keybd_event(VK_MENU, 0, 0, 0);
9141 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9142 keybd_event(VK_MENU, 0, 0, 0);
9143 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9144 pump_msg_loop(hwnd, 0);
9145 /* this test doesn't pass in Wine for managed windows */
9146 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
9147
9148 trace("testing VK_F1 press/release\n");
9149 keybd_event(VK_F1, 0, 0, 0);
9150 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9151 pump_msg_loop(hwnd, 0);
9152 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9153
9154 trace("testing VK_APPS press/release\n");
9155 keybd_event(VK_APPS, 0, 0, 0);
9156 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9157 pump_msg_loop(hwnd, 0);
9158 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9159
9160 trace("testing VK_F10 press/release\n");
9161 keybd_event(VK_F10, 0, 0, 0);
9162 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9163 keybd_event(VK_F10, 0, 0, 0);
9164 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9165 pump_msg_loop(hwnd, 0);
9166 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
9167
9168 trace("testing SHIFT+F10 press/release\n");
9169 keybd_event(VK_SHIFT, 0, 0, 0);
9170 keybd_event(VK_F10, 0, 0, 0);
9171 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9172 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9173 keybd_event(VK_ESCAPE, 0, 0, 0);
9174 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9175 pump_msg_loop(hwnd, 0);
9176 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9177
9178 trace("testing Shift+MouseButton press/release\n");
9179 /* first, move mouse pointer inside of the window client area */
9180 GetClientRect(hwnd, &rc);
9181 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9182 rc.left += (rc.right - rc.left)/2;
9183 rc.top += (rc.bottom - rc.top)/2;
9184 SetCursorPos(rc.left, rc.top);
9185 SetActiveWindow(hwnd);
9186
9187 flush_events();
9188 flush_sequence();
9189 GetCursorPos(&pt);
9190 if (pt.x == rc.left && pt.y == rc.top)
9191 {
9192 int i;
9193 keybd_event(VK_SHIFT, 0, 0, 0);
9194 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9195 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9196 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9197 pump_msg_loop(hwnd, 0);
9198 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9199 if (i < sequence_cnt)
9200 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9201 else
9202 skip( "Shift+MouseButton event didn't get to the window\n" );
9203 }
9204
9205 done:
9206 if (hAccel) DestroyAcceleratorTable(hAccel);
9207 DestroyWindow(hwnd);
9208 }
9209
9210 /************* window procedures ********************/
9211
9212 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9213 WPARAM wParam, LPARAM lParam)
9214 {
9215 static LONG defwndproc_counter = 0;
9216 static LONG beginpaint_counter = 0;
9217 LRESULT ret;
9218 struct recvd_message msg;
9219
9220 if (ignore_message( message )) return 0;
9221
9222 switch (message)
9223 {
9224 case WM_ENABLE:
9225 {
9226 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9227 ok((BOOL)wParam == !(style & WS_DISABLED),
9228 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9229 break;
9230 }
9231
9232 case WM_CAPTURECHANGED:
9233 if (test_DestroyWindow_flag)
9234 {
9235 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9236 if (style & WS_CHILD)
9237 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9238 else if (style & WS_POPUP)
9239 lParam = WND_POPUP_ID;
9240 else
9241 lParam = WND_PARENT_ID;
9242 }
9243 break;
9244
9245 case WM_NCDESTROY:
9246 {
9247 HWND capture;
9248
9249 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9250 capture = GetCapture();
9251 if (capture)
9252 {
9253 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9254 trace("current capture %p, releasing...\n", capture);
9255 ReleaseCapture();
9256 }
9257 }
9258 /* fall through */
9259 case WM_DESTROY:
9260 if (pGetAncestor)
9261 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9262 if (test_DestroyWindow_flag)
9263 {
9264 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9265 if (style & WS_CHILD)
9266 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9267 else if (style & WS_POPUP)
9268 lParam = WND_POPUP_ID;
9269 else
9270 lParam = WND_PARENT_ID;
9271 }
9272 break;
9273
9274 /* test_accelerators() depends on this */
9275 case WM_NCHITTEST:
9276 return HTCLIENT;
9277
9278 case WM_USER+10:
9279 {
9280 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9281 HANDLE handle, event = (HANDLE)lParam;
9282 BOOL ret;
9283
9284 handle = (void*)0xdeadbeef;
9285 ret = pGetCurrentActCtx(&handle);
9286 ok(ret, "failed to get current context, %u\n", GetLastError());
9287 ok(handle == 0, "got active context %p\n", handle);
9288
9289 memset(&basicinfo, 0xff, sizeof(basicinfo));
9290 ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9291 &basicinfo, sizeof(basicinfo), NULL);
9292 ok(ret, "got %d, error %d\n", ret, GetLastError());
9293 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9294 ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9295
9296 if (event) SetEvent(event);
9297 return 1;
9298 }
9299
9300 /* ignore */
9301 case WM_MOUSEMOVE:
9302 case WM_MOUSEACTIVATE:
9303 case WM_NCMOUSEMOVE:
9304 case WM_SETCURSOR:
9305 case WM_IME_SELECT:
9306 return 0;
9307 }
9308
9309 msg.hwnd = hwnd;
9310 msg.message = message;
9311 msg.flags = sent|wparam|lparam;
9312 if (defwndproc_counter) msg.flags |= defwinproc;
9313 if (beginpaint_counter) msg.flags |= beginpaint;
9314 msg.wParam = wParam;
9315 msg.lParam = lParam;
9316 msg.descr = "MsgCheckProc";
9317 add_message(&msg);
9318
9319 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9320 {
9321 HWND parent = GetParent(hwnd);
9322 RECT rc;
9323 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9324
9325 GetClientRect(parent, &rc);
9326 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9327 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9328 minmax->ptReserved.x, minmax->ptReserved.y,
9329 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9330 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9331 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9332 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9333
9334 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9335 minmax->ptMaxSize.x, rc.right);
9336 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9337 minmax->ptMaxSize.y, rc.bottom);
9338 }
9339
9340 if (message == WM_PAINT)
9341 {
9342 PAINTSTRUCT ps;
9343 beginpaint_counter++;
9344 BeginPaint( hwnd, &ps );
9345 beginpaint_counter--;
9346 EndPaint( hwnd, &ps );
9347 return 0;
9348 }
9349
9350 if (message == WM_CONTEXTMENU)
9351 {
9352 /* don't create context menu */
9353 return 0;
9354 }
9355
9356 defwndproc_counter++;
9357 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9358 : DefWindowProcA(hwnd, message, wParam, lParam);
9359 defwndproc_counter--;
9360
9361 return ret;
9362 }
9363
9364 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9365 {
9366 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9367 }
9368
9369 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9370 {
9371 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9372 }
9373
9374 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9375 {
9376 static LONG defwndproc_counter = 0;
9377 LRESULT ret;
9378 struct recvd_message msg;
9379
9380 if (ignore_message( message )) return 0;
9381
9382 switch (message)
9383 {
9384 case WM_QUERYENDSESSION:
9385 case WM_ENDSESSION:
9386 lParam &= ~0x01; /* Vista adds a 0x01 flag */
9387 break;
9388 }
9389
9390 msg.hwnd = hwnd;
9391 msg.message = message;
9392 msg.flags = sent|wparam|lparam;
9393 if (defwndproc_counter) msg.flags |= defwinproc;
9394 msg.wParam = wParam;
9395 msg.lParam = lParam;
9396 msg.descr = "popup";
9397 add_message(&msg);
9398
9399 if (message == WM_CREATE)
9400 {
9401 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9402 SetWindowLongA(hwnd, GWL_STYLE, style);
9403 }
9404
9405 defwndproc_counter++;
9406 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9407 defwndproc_counter--;
9408
9409 return ret;
9410 }
9411
9412 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9413 {
9414 static LONG defwndproc_counter = 0;
9415 static LONG beginpaint_counter = 0;
9416 LRESULT ret;
9417 struct recvd_message msg;
9418
9419 if (ignore_message( message )) return 0;
9420
9421 if (log_all_parent_messages ||
9422 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9423 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9424 message == WM_ENABLE || message == WM_ENTERIDLE ||
9425 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9426 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9427 {
9428 switch (message)
9429 {
9430 /* ignore */
9431 case WM_NCHITTEST:
9432 return HTCLIENT;
9433 case WM_SETCURSOR:
9434 case WM_MOUSEMOVE:
9435 case WM_NCMOUSEMOVE:
9436 return 0;
9437
9438 case WM_ERASEBKGND:
9439 {
9440 RECT rc;
9441 INT ret = GetClipBox((HDC)wParam, &rc);
9442
9443 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9444 break;
9445 }
9446 }
9447
9448 msg.hwnd = hwnd;
9449 msg.message = message;
9450 msg.flags = sent|parent|wparam|lparam;
9451 if (defwndproc_counter) msg.flags |= defwinproc;
9452 if (beginpaint_counter) msg.flags |= beginpaint;
9453 msg.wParam = wParam;
9454 msg.lParam = lParam;
9455 msg.descr = "parent";
9456 add_message(&msg);
9457 }
9458
9459 if (message == WM_PAINT)
9460 {
9461 PAINTSTRUCT ps;
9462 beginpaint_counter++;
9463 BeginPaint( hwnd, &ps );
9464 beginpaint_counter--;
9465 EndPaint( hwnd, &ps );
9466 return 0;
9467 }
9468
9469 defwndproc_counter++;
9470 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9471 defwndproc_counter--;
9472
9473 return message == WM_COMPAREITEM ? -1 : ret;
9474 }
9475
9476 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9477 {
9478 if (message == WM_CREATE)
9479 PostMessageA(hwnd, WM_CLOSE, 0, 0);
9480 else if (message == WM_CLOSE)
9481 {
9482 /* Only the first WM_QUIT will survive the window destruction */
9483 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9484 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9485 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9486 }
9487
9488 return DefWindowProcA(hwnd, message, wp, lp);
9489 }
9490
9491 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9492 {
9493 static LONG defwndproc_counter = 0;
9494 LRESULT ret;
9495 struct recvd_message msg;
9496
9497 if (ignore_message( message )) return 0;
9498
9499 if (test_def_id)
9500 {
9501 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9502 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9503 if (after_end_dialog)
9504 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9505 else
9506 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9507 }
9508
9509 msg.hwnd = hwnd;
9510 msg.message = message;
9511 msg.flags = sent|wparam|lparam;
9512 if (defwndproc_counter) msg.flags |= defwinproc;
9513 msg.wParam = wParam;
9514 msg.lParam = lParam;
9515 msg.descr = "dialog";
9516 add_message(&msg);
9517
9518 defwndproc_counter++;
9519 ret = DefDlgProcA(hwnd, message, wParam, lParam);
9520 defwndproc_counter--;
9521
9522 return ret;
9523 }
9524
9525 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9526 {
9527 static LONG defwndproc_counter = 0;
9528 LRESULT ret;
9529 struct recvd_message msg;
9530
9531 /* log only specific messages we are interested in */
9532 switch (message)
9533 {
9534 #if 0 /* probably log these as well */
9535 case WM_ACTIVATE:
9536 case WM_SETFOCUS:
9537 case WM_KILLFOCUS:
9538 #endif
9539 case WM_SHOWWINDOW:
9540 case WM_SIZE:
9541 case WM_MOVE:
9542 case WM_GETMINMAXINFO:
9543 case WM_WINDOWPOSCHANGING:
9544 case WM_WINDOWPOSCHANGED:
9545 break;
9546
9547 default: /* ignore */
9548 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9549 return DefWindowProcA(hwnd, message, wParam, lParam);
9550 }
9551
9552 msg.hwnd = hwnd;
9553 msg.message = message;
9554 msg.flags = sent|wparam|lparam;
9555 if (defwndproc_counter) msg.flags |= defwinproc;
9556 msg.wParam = wParam;
9557 msg.lParam = lParam;
9558 msg.descr = "show";
9559 add_message(&msg);
9560
9561 defwndproc_counter++;
9562 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9563 defwndproc_counter--;
9564
9565 return ret;
9566 }
9567
9568 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
9569 {
9570 switch (msg)
9571 {
9572 case WM_CREATE: return 0;
9573 case WM_PAINT:
9574 {
9575 MSG msg2;
9576 static int i = 0;
9577
9578 if (i < 256)
9579 {
9580 i++;
9581 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9582 {
9583 TranslateMessage(&msg2);
9584 DispatchMessageA(&msg2);
9585 }
9586 i--;
9587 }
9588 else ok(broken(1), "infinite loop\n");
9589 if ( i == 0)
9590 paint_loop_done = TRUE;
9591 return DefWindowProcA(hWnd,msg,wParam,lParam);
9592 }
9593 }
9594 return DefWindowProcA(hWnd,msg,wParam,lParam);
9595 }
9596
9597 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9598 {
9599 static LONG defwndproc_counter = 0;
9600 LRESULT ret;
9601 struct recvd_message msg;
9602 DWORD queue_status;
9603
9604 if (ignore_message( message )) return 0;
9605
9606 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9607 message == WM_HOTKEY || message >= WM_APP)
9608 {
9609 msg.hwnd = hwnd;
9610 msg.message = message;
9611 msg.flags = sent|wparam|lparam;
9612 if (defwndproc_counter) msg.flags |= defwinproc;
9613 msg.wParam = wParam;
9614 msg.lParam = lParam;
9615 msg.descr = "HotkeyMsgCheckProcA";
9616 add_message(&msg);
9617 }
9618
9619 defwndproc_counter++;
9620 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9621 defwndproc_counter--;
9622
9623 if (message == WM_APP)
9624 {
9625 queue_status = GetQueueStatus(QS_HOTKEY);
9626 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9627 queue_status = GetQueueStatus(QS_POSTMESSAGE);
9628 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9629 PostMessageA(hwnd, WM_APP+1, 0, 0);
9630 }
9631 else if (message == WM_APP+1)
9632 {
9633 queue_status = GetQueueStatus(QS_HOTKEY);
9634 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9635 }
9636
9637 return ret;
9638 }
9639
9640 static BOOL RegisterWindowClasses(void)
9641 {
9642 WNDCLASSA cls;
9643 WNDCLASSW clsW;
9644
9645 cls.style = 0;
9646 cls.lpfnWndProc = MsgCheckProcA;
9647 cls.cbClsExtra = 0;
9648 cls.cbWndExtra = 0;
9649 cls.hInstance = GetModuleHandleA(0);
9650 cls.hIcon = 0;
9651 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9652 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9653 cls.lpszMenuName = NULL;
9654 cls.lpszClassName = "TestWindowClass";
9655 if(!RegisterClassA(&cls)) return FALSE;
9656
9657 cls.lpfnWndProc = HotkeyMsgCheckProcA;
9658 cls.lpszClassName = "HotkeyWindowClass";
9659 if(!RegisterClassA(&cls)) return FALSE;
9660
9661 cls.lpfnWndProc = ShowWindowProcA;
9662 cls.lpszClassName = "ShowWindowClass";
9663 if(!RegisterClassA(&cls)) return FALSE;
9664
9665 cls.lpfnWndProc = PopupMsgCheckProcA;
9666 cls.lpszClassName = "TestPopupClass";
9667 if(!RegisterClassA(&cls)) return FALSE;
9668
9669 cls.lpfnWndProc = ParentMsgCheckProcA;
9670 cls.lpszClassName = "TestParentClass";
9671 if(!RegisterClassA(&cls)) return FALSE;
9672
9673 cls.lpfnWndProc = StopQuitMsgCheckProcA;
9674 cls.lpszClassName = "StopQuitClass";
9675 if(!RegisterClassA(&cls)) return FALSE;
9676
9677 cls.lpfnWndProc = DefWindowProcA;
9678 cls.lpszClassName = "SimpleWindowClass";
9679 if(!RegisterClassA(&cls)) return FALSE;
9680
9681 cls.lpfnWndProc = PaintLoopProcA;
9682 cls.lpszClassName = "PaintLoopWindowClass";
9683 if(!RegisterClassA(&cls)) return FALSE;
9684
9685 cls.style = CS_NOCLOSE;
9686 cls.lpszClassName = "NoCloseWindowClass";
9687 if(!RegisterClassA(&cls)) return FALSE;
9688
9689 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9690 cls.style = 0;
9691 cls.hInstance = GetModuleHandleA(0);
9692 cls.hbrBackground = 0;
9693 cls.lpfnWndProc = TestDlgProcA;
9694 cls.lpszClassName = "TestDialogClass";
9695 if(!RegisterClassA(&cls)) return FALSE;
9696
9697 clsW.style = 0;
9698 clsW.lpfnWndProc = MsgCheckProcW;
9699 clsW.cbClsExtra = 0;
9700 clsW.cbWndExtra = 0;
9701 clsW.hInstance = GetModuleHandleW(0);
9702 clsW.hIcon = 0;
9703 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9704 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9705 clsW.lpszMenuName = NULL;
9706 clsW.lpszClassName = testWindowClassW;
9707 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
9708
9709 return TRUE;
9710 }
9711
9712 static BOOL is_our_logged_class(HWND hwnd)
9713 {
9714 char buf[256];
9715
9716 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9717 {
9718 if (!lstrcmpiA(buf, "TestWindowClass") ||
9719 !lstrcmpiA(buf, "ShowWindowClass") ||
9720 !lstrcmpiA(buf, "TestParentClass") ||
9721 !lstrcmpiA(buf, "TestPopupClass") ||
9722 !lstrcmpiA(buf, "SimpleWindowClass") ||
9723 !lstrcmpiA(buf, "TestDialogClass") ||
9724 !lstrcmpiA(buf, "MDI_frame_class") ||
9725 !lstrcmpiA(buf, "MDI_client_class") ||
9726 !lstrcmpiA(buf, "MDI_child_class") ||
9727 !lstrcmpiA(buf, "my_button_class") ||
9728 !lstrcmpiA(buf, "my_edit_class") ||
9729 !lstrcmpiA(buf, "static") ||
9730 !lstrcmpiA(buf, "ListBox") ||
9731 !lstrcmpiA(buf, "ComboBox") ||
9732 !lstrcmpiA(buf, "MyDialogClass") ||
9733 !lstrcmpiA(buf, "#32770") ||
9734 !lstrcmpiA(buf, "#32768"))
9735 return TRUE;
9736 }
9737 return FALSE;
9738 }
9739
9740 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9741 {
9742 HWND hwnd;
9743
9744 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9745
9746 if (nCode == HCBT_CLICKSKIPPED)
9747 {
9748 /* ignore this event, XP sends it a lot when switching focus between windows */
9749 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9750 }
9751
9752 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9753 {
9754 struct recvd_message msg;
9755
9756 msg.hwnd = 0;
9757 msg.message = nCode;
9758 msg.flags = hook|wparam|lparam;
9759 msg.wParam = wParam;
9760 msg.lParam = lParam;
9761 msg.descr = "CBT";
9762 add_message(&msg);
9763
9764 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9765 }
9766
9767 if (nCode == HCBT_DESTROYWND)
9768 {
9769 if (test_DestroyWindow_flag)
9770 {
9771 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9772 if (style & WS_CHILD)
9773 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9774 else if (style & WS_POPUP)
9775 lParam = WND_POPUP_ID;
9776 else
9777 lParam = WND_PARENT_ID;
9778 }
9779 }
9780
9781 /* Log also SetFocus(0) calls */
9782 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9783
9784 if (is_our_logged_class(hwnd))
9785 {
9786 struct recvd_message msg;
9787
9788 msg.hwnd = hwnd;
9789 msg.message = nCode;
9790 msg.flags = hook|wparam|lparam;
9791 msg.wParam = wParam;
9792 msg.lParam = lParam;
9793 msg.descr = "CBT";
9794 add_message(&msg);
9795 }
9796 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9797 }
9798
9799 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
9800 DWORD event,
9801 HWND hwnd,
9802 LONG object_id,
9803 LONG child_id,
9804 DWORD thread_id,
9805 DWORD event_time)
9806 {
9807 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9808
9809 /* ignore mouse cursor events */
9810 if (object_id == OBJID_CURSOR) return;
9811
9812 if (!hwnd || is_our_logged_class(hwnd))
9813 {
9814 struct recvd_message msg;
9815
9816 msg.hwnd = hwnd;
9817 msg.message = event;
9818 msg.flags = winevent_hook|wparam|lparam;
9819 msg.wParam = object_id;
9820 msg.lParam = child_id;
9821 msg.descr = "WEH";
9822 add_message(&msg);
9823 }
9824 }
9825
9826 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
9827 static const WCHAR wszAnsi[] = {'U',0};
9828
9829 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
9830 {
9831 switch (uMsg)
9832 {
9833 case CB_FINDSTRINGEXACT:
9834 trace("String: %p\n", (LPCWSTR)lParam);
9835 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
9836 return 1;
9837 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
9838 return 0;
9839 return -1;
9840 }
9841 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
9842 }
9843
9844 static const struct message WmGetTextLengthAfromW[] = {
9845 { WM_GETTEXTLENGTH, sent },
9846 { WM_GETTEXT, sent|optional },
9847 { 0 }
9848 };
9849
9850 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
9851
9852 /* dummy window proc for WM_GETTEXTLENGTH test */
9853 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
9854 {
9855 switch(msg)
9856 {
9857 case WM_GETTEXTLENGTH:
9858 return lstrlenW(dummy_window_text) + 37; /* some random length */
9859 case WM_GETTEXT:
9860 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
9861 return lstrlenW( (LPWSTR)lp );
9862 default:
9863 return DefWindowProcW( hwnd, msg, wp, lp );
9864 }
9865 }
9866
9867 static void test_message_conversion(void)
9868 {
9869 static const WCHAR wszMsgConversionClass[] =
9870 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
9871 WNDCLASSW cls;
9872 LRESULT lRes;
9873 HWND hwnd;
9874 WNDPROC wndproc, newproc;
9875 BOOL ret;
9876
9877 cls.style = 0;
9878 cls.lpfnWndProc = MsgConversionProcW;
9879 cls.cbClsExtra = 0;
9880 cls.cbWndExtra = 0;
9881 cls.hInstance = GetModuleHandleW(NULL);
9882 cls.hIcon = NULL;
9883 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
9884 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
9885 cls.lpszMenuName = NULL;
9886 cls.lpszClassName = wszMsgConversionClass;
9887 /* this call will fail on Win9x, but that doesn't matter as this test is
9888 * meaningless on those platforms */
9889 if(!RegisterClassW(&cls)) return;
9890
9891 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
9892 100, 100, 200, 200, 0, 0, 0, NULL);
9893 ok(hwnd != NULL, "Window creation failed\n");
9894
9895 /* {W, A} -> A */
9896
9897 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
9898 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9899 ok(lRes == 0, "String should have been converted\n");
9900 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9901 ok(lRes == 1, "String shouldn't have been converted\n");
9902
9903 /* {W, A} -> W */
9904
9905 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
9906 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9907 ok(lRes == 1, "String shouldn't have been converted\n");
9908 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9909 ok(lRes == 1, "String shouldn't have been converted\n");
9910
9911 /* Synchronous messages */
9912
9913 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9914 ok(lRes == 0, "String should have been converted\n");
9915 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9916 ok(lRes == 1, "String shouldn't have been converted\n");
9917
9918 /* Asynchronous messages */
9919
9920 SetLastError(0);
9921 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9922 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9923 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9924 SetLastError(0);
9925 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9926 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9927 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9928 SetLastError(0);
9929 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9930 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9931 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9932 SetLastError(0);
9933 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9934 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9935 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9936 SetLastError(0);
9937 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9938 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9939 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9940 SetLastError(0);
9941 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9942 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9943 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9944 SetLastError(0);
9945 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9946 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9947 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9948 SetLastError(0);
9949 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9950 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9951 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9952
9953 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
9954
9955 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
9956 WS_OVERLAPPEDWINDOW,
9957 100, 100, 200, 200, 0, 0, 0, NULL);
9958 assert(hwnd);
9959 flush_sequence();
9960 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
9961 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9962 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9963 "got bad length %ld\n", lRes );
9964
9965 flush_sequence();
9966 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
9967 hwnd, WM_GETTEXTLENGTH, 0, 0);
9968 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9969 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9970 "got bad length %ld\n", lRes );
9971
9972 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
9973 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
9974 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9975 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9976 NULL, 0, NULL, NULL ) ||
9977 broken(lRes == lstrlenW(dummy_window_text) + 37),
9978 "got bad length %ld\n", lRes );
9979
9980 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
9981 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9982 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9983 NULL, 0, NULL, NULL ) ||
9984 broken(lRes == lstrlenW(dummy_window_text) + 37),
9985 "got bad length %ld\n", lRes );
9986
9987 ret = DestroyWindow(hwnd);
9988 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9989 }
9990
9991 struct timer_info
9992 {
9993 HWND hWnd;
9994 HANDLE handles[2];
9995 DWORD id;
9996 };
9997
9998 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
9999 {
10000 }
10001
10002 #define TIMER_ID 0x19
10003 #define TIMER_COUNT_EXPECTED 100
10004 #define TIMER_COUNT_TOLERANCE 10
10005
10006 static int count = 0;
10007 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10008 {
10009 count++;
10010 }
10011
10012 static DWORD exception;
10013 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10014 {
10015 count++;
10016 RaiseException(exception, 0, 0, NULL);
10017 }
10018
10019 static DWORD WINAPI timer_thread_proc(LPVOID x)
10020 {
10021 struct timer_info *info = x;
10022 DWORD r;
10023
10024 r = KillTimer(info->hWnd, 0x19);
10025 ok(r,"KillTimer failed in thread\n");
10026 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
10027 ok(r,"SetTimer failed in thread\n");
10028 ok(r==TIMER_ID,"SetTimer id different\n");
10029 r = SetEvent(info->handles[0]);
10030 ok(r,"SetEvent failed in thread\n");
10031 return 0;
10032 }
10033
10034 static void test_timers(void)
10035 {
10036 struct timer_info info;
10037 DWORD start;
10038 DWORD id;
10039 MSG msg;
10040
10041 info.hWnd = CreateWindowA("TestWindowClass", NULL,
10042 WS_OVERLAPPEDWINDOW ,
10043 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10044 NULL, NULL, 0);
10045
10046 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
10047 ok(info.id, "SetTimer failed\n");
10048 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
10049 info.handles[0] = CreateEventW(NULL,0,0,NULL);
10050 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
10051
10052 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
10053
10054 WaitForSingleObject(info.handles[1], INFINITE);
10055
10056 CloseHandle(info.handles[0]);
10057 CloseHandle(info.handles[1]);
10058
10059 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
10060
10061 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10062 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10063 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10064 * ±9 counts (~4 ms) around the expected value.
10065 */
10066 count = 0;
10067 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
10068 ok(id != 0, "did not get id from SetTimer.\n");
10069 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10070 start = GetTickCount();
10071 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10072 DispatchMessageA(&msg);
10073 todo_wine
10074 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10075 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
10076 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
10077 "did not get expected count for minimum timeout (%d != ~%d).\n",
10078 count, TIMER_COUNT_EXPECTED);
10079 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
10080 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
10081 if (pSetSystemTimer)
10082 {
10083 int syscount = 0;
10084
10085 count = 0;
10086 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
10087 ok(id != 0, "did not get id from SetSystemTimer.\n");
10088 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10089 start = GetTickCount();
10090 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10091 {
10092 if (msg.message == WM_SYSTIMER)
10093 syscount++;
10094 DispatchMessageA(&msg);
10095 }
10096 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
10097 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
10098 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
10099 "did not get expected count for minimum timeout (%d != ~%d).\n",
10100 syscount, TIMER_COUNT_EXPECTED);
10101 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
10102 count);
10103 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10104 }
10105
10106 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10107 }
10108
10109 static void test_timers_no_wnd(void)
10110 {
10111 static UINT_PTR ids[0xffff];
10112 UINT_PTR id, id2;
10113 DWORD start;
10114 MSG msg;
10115 int i;
10116
10117 count = 0;
10118 id = SetTimer(NULL, 0, 100, callback_count);
10119 ok(id != 0, "did not get id from SetTimer.\n");
10120 id2 = SetTimer(NULL, id, 200, callback_count);
10121 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10122 Sleep(150);
10123 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10124 ok(count == 0, "did not get zero count as expected (%i).\n", count);
10125 Sleep(150);
10126 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10127 ok(count == 1, "did not get one count as expected (%i).\n", count);
10128 KillTimer(NULL, id);
10129 Sleep(250);
10130 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10131 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10132
10133 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10134 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10135 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10136 * ±9 counts (~4 ms) around the expected value.
10137 */
10138 count = 0;
10139 id = SetTimer(NULL, 0, 0, callback_count);
10140 ok(id != 0, "did not get id from SetTimer.\n");
10141 start = GetTickCount();
10142 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10143 DispatchMessageA(&msg);
10144 todo_wine
10145 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10146 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
10147 "did not get expected count for minimum timeout (%d != ~%d).\n",
10148 count, TIMER_COUNT_EXPECTED);
10149 KillTimer(NULL, id);
10150 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10151
10152 if (pSetCoalescableTimer)
10153 {
10154 count = 0;
10155 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10156 ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10157 start = GetTickCount();
10158 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10159 DispatchMessageA(&msg);
10160 ok(count > 1, "expected count > 1, got %d.\n", count);
10161 KillTimer(NULL, id);
10162 }
10163 else
10164 win_skip("SetCoalescableTimer not available.\n");
10165
10166 /* Check what happens when we're running out of timers */
10167 for (i=0; i<sizeof(ids)/sizeof(ids[0]); i++)
10168 {
10169 SetLastError(0xdeadbeef);
10170 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10171 if (!ids[i]) break;
10172 }
10173 ok(i != sizeof(ids)/sizeof(ids[0]), "all timers were created successfully\n");
10174 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10175 "GetLastError() = %d\n", GetLastError());
10176 while (i > 0) KillTimer(NULL, ids[--i]);
10177 }
10178
10179 static void test_timers_exception(DWORD code)
10180 {
10181 UINT_PTR id;
10182 MSG msg;
10183
10184 exception = code;
10185 id = SetTimer(NULL, 0, 1000, callback_exception);
10186 ok(id != 0, "did not get id from SetTimer.\n");
10187
10188 memset(&msg, 0, sizeof(msg));
10189 msg.message = WM_TIMER;
10190 msg.wParam = id;
10191 msg.lParam = (LPARAM)callback_exception;
10192
10193 count = 0;
10194 DispatchMessageA(&msg);
10195 ok(count == 1, "did not get one count as expected (%i).\n", count);
10196
10197 KillTimer(NULL, id);
10198 }
10199
10200 static void test_timers_exceptions(void)
10201 {
10202 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10203 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10204 test_timers_exception(EXCEPTION_BREAKPOINT);
10205 test_timers_exception(EXCEPTION_SINGLE_STEP);
10206 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10207 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10208 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10209 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10210 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10211 test_timers_exception(0xE000BEEF); /* customer exception */
10212 }
10213
10214 /* Various win events with arbitrary parameters */
10215 static const struct message WmWinEventsSeq[] = {
10216 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10217 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10218 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10219 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10220 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10221 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10222 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10223 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10224 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10225 /* our win event hook ignores OBJID_CURSOR events */
10226 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10227 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10228 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10229 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10230 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10231 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10232 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10233 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10234 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10235 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10236 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10237 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10238 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10239 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10240 { 0 }
10241 };
10242 static const struct message WmWinEventCaretSeq[] = {
10243 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10244 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10245 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10246 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10247 { 0 }
10248 };
10249 static const struct message WmWinEventCaretSeq_2[] = {
10250 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10251 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10252 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10253 { 0 }
10254 };
10255 static const struct message WmWinEventAlertSeq[] = {
10256 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10257 { 0 }
10258 };
10259 static const struct message WmWinEventAlertSeq_2[] = {
10260 /* create window in the thread proc */
10261 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10262 /* our test event */
10263 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10264 { 0 }
10265 };
10266 static const struct message WmGlobalHookSeq_1[] = {
10267 /* create window in the thread proc */
10268 { HCBT_CREATEWND, hook|lparam, 0, 2 },
10269 /* our test events */
10270 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10271 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10272 { 0 }
10273 };
10274 static const struct message WmGlobalHookSeq_2[] = {
10275 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10276 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10277 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10278 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10279 { 0 }
10280 };
10281
10282 static const struct message WmMouseLLHookSeq[] = {
10283 { WM_MOUSEMOVE, hook },
10284 { WM_LBUTTONUP, hook },
10285 { WM_MOUSEMOVE, hook },
10286 { 0 }
10287 };
10288
10289 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10290 DWORD event,
10291 HWND hwnd,
10292 LONG object_id,
10293 LONG child_id,
10294 DWORD thread_id,
10295 DWORD event_time)
10296 {
10297 char buf[256];
10298
10299 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10300 {
10301 if (!lstrcmpiA(buf, "TestWindowClass") ||
10302 !lstrcmpiA(buf, "static"))
10303 {
10304 struct recvd_message msg;
10305
10306 msg.hwnd = hwnd;
10307 msg.message = event;
10308 msg.flags = winevent_hook|wparam|lparam;
10309 msg.wParam = object_id;
10310 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10311 msg.descr = "WEH_2";
10312 add_message(&msg);
10313 }
10314 }
10315 }
10316
10317 static HHOOK hCBT_global_hook;
10318 static DWORD cbt_global_hook_thread_id;
10319
10320 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10321 {
10322 HWND hwnd;
10323 char buf[256];
10324
10325 if (nCode == HCBT_SYSCOMMAND)
10326 {
10327 struct recvd_message msg;
10328
10329 msg.hwnd = 0;
10330 msg.message = nCode;
10331 msg.flags = hook|wparam|lparam;
10332 msg.wParam = wParam;
10333 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10334 msg.descr = "CBT_2";
10335 add_message(&msg);
10336
10337 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10338 }
10339 /* WH_MOUSE_LL hook */
10340 if (nCode == HC_ACTION)
10341 {
10342 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10343
10344 /* we can't test for real mouse events */
10345 if (mhll->flags & LLMHF_INJECTED)
10346 {
10347 struct recvd_message msg;
10348
10349 memset (&msg, 0, sizeof (msg));
10350 msg.message = wParam;
10351 msg.flags = hook;
10352 msg.descr = "CBT_2";
10353 add_message(&msg);
10354 }
10355 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10356 }
10357
10358 /* Log also SetFocus(0) calls */
10359 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10360
10361 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10362 {
10363 if (!lstrcmpiA(buf, "TestWindowClass") ||
10364 !lstrcmpiA(buf, "static"))
10365 {
10366 struct recvd_message msg;
10367
10368 msg.hwnd = hwnd;
10369 msg.message = nCode;
10370 msg.flags = hook|wparam|lparam;
10371 msg.wParam = wParam;
10372 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10373 msg.descr = "CBT_2";
10374 add_message(&msg);
10375 }
10376 }
10377 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10378 }
10379
10380 static DWORD WINAPI win_event_global_thread_proc(void *param)
10381 {
10382 HWND hwnd;
10383 MSG msg;
10384 HANDLE hevent = *(HANDLE *)param;
10385
10386 assert(pNotifyWinEvent);
10387
10388 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10389 assert(hwnd);
10390 trace("created thread window %p\n", hwnd);
10391
10392 *(HWND *)param = hwnd;
10393
10394 flush_sequence();
10395 /* this event should be received only by our new hook proc,
10396 * an old one does not expect an event from another thread.
10397 */
10398 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10399 SetEvent(hevent);
10400
10401 while (GetMessageA(&msg, 0, 0, 0))
10402 {
10403 TranslateMessage(&msg);
10404 DispatchMessageA(&msg);
10405 }
10406 return 0;
10407 }
10408
10409 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10410 {
10411 HWND hwnd;
10412 MSG msg;
10413 HANDLE hevent = *(HANDLE *)param;
10414
10415 flush_sequence();
10416 /* these events should be received only by our new hook proc,
10417 * an old one does not expect an event from another thread.
10418 */
10419
10420 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10421 assert(hwnd);
10422 trace("created thread window %p\n", hwnd);
10423
10424 *(HWND *)param = hwnd;
10425
10426 /* Windows doesn't like when a thread plays games with the focus,
10427 that leads to all kinds of misbehaviours and failures to activate
10428 a window. So, better keep next lines commented out.
10429 SetFocus(0);
10430 SetFocus(hwnd);*/
10431
10432 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10433 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10434
10435 SetEvent(hevent);
10436
10437 while (GetMessageA(&msg, 0, 0, 0))
10438 {
10439 TranslateMessage(&msg);
10440 DispatchMessageA(&msg);
10441 }
10442 return 0;
10443 }
10444
10445 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10446 {
10447 HWND hwnd;
10448 MSG msg;
10449 HANDLE hevent = *(HANDLE *)param;
10450
10451 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10452 assert(hwnd);
10453 trace("created thread window %p\n", hwnd);
10454
10455 *(HWND *)param = hwnd;
10456
10457 flush_sequence();
10458
10459 /* Windows doesn't like when a thread plays games with the focus,
10460 * that leads to all kinds of misbehaviours and failures to activate
10461 * a window. So, better don't generate a mouse click message below.
10462 */
10463 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10464 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10465 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10466
10467 SetEvent(hevent);
10468 while (GetMessageA(&msg, 0, 0, 0))
10469 {
10470 TranslateMessage(&msg);
10471 DispatchMessageA(&msg);
10472 }
10473 return 0;
10474 }
10475
10476 static void test_winevents(void)
10477 {
10478 BOOL ret;
10479 MSG msg;
10480 HWND hwnd, hwnd2;
10481 UINT i;
10482 HANDLE hthread, hevent;
10483 DWORD tid;
10484 HWINEVENTHOOK hhook;
10485 const struct message *events = WmWinEventsSeq;
10486
10487 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10488 WS_OVERLAPPEDWINDOW,
10489 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10490 NULL, NULL, 0);
10491 assert(hwnd);
10492
10493 /****** start of global hook test *************/
10494 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10495 if (!hCBT_global_hook)
10496 {
10497 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10498 skip( "cannot set global hook\n" );
10499 return;
10500 }
10501
10502 hevent = CreateEventA(NULL, 0, 0, NULL);
10503 assert(hevent);
10504 hwnd2 = hevent;
10505
10506 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10507 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10508
10509 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10510
10511 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10512
10513 flush_sequence();
10514 /* this one should be received only by old hook proc */
10515 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10516 /* this one should be received only by old hook proc */
10517 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10518
10519 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10520
10521 ret = UnhookWindowsHookEx(hCBT_global_hook);
10522 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10523
10524 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10525 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10526 CloseHandle(hthread);
10527 CloseHandle(hevent);
10528 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10529 /****** end of global hook test *************/
10530
10531 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10532 {
10533 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10534 return;
10535 }
10536
10537 flush_sequence();
10538
10539 if (0)
10540 {
10541 /* this test doesn't pass under Win9x */
10542 /* win2k ignores events with hwnd == 0 */
10543 SetLastError(0xdeadbeef);
10544 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10545 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10546 GetLastError() == 0xdeadbeef, /* Win9x */
10547 "unexpected error %d\n", GetLastError());
10548 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10549 }
10550
10551 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
10552 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10553
10554 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10555
10556 /****** start of event filtering test *************/
10557 hhook = pSetWinEventHook(
10558 EVENT_OBJECT_SHOW, /* 0x8002 */
10559 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10560 GetModuleHandleA(0), win_event_global_hook_proc,
10561 GetCurrentProcessId(), 0,
10562 WINEVENT_INCONTEXT);
10563 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10564
10565 hevent = CreateEventA(NULL, 0, 0, NULL);
10566 assert(hevent);
10567 hwnd2 = hevent;
10568
10569 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10570 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10571
10572 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10573
10574 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10575
10576 flush_sequence();
10577 /* this one should be received only by old hook proc */
10578 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10579 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10580 /* this one should be received only by old hook proc */
10581 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10582
10583 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10584
10585 ret = pUnhookWinEvent(hhook);
10586 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10587
10588 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10589 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10590 CloseHandle(hthread);
10591 CloseHandle(hevent);
10592 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10593 /****** end of event filtering test *************/
10594
10595 /****** start of out of context event test *************/
10596 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10597 win_event_global_hook_proc, GetCurrentProcessId(), 0,
10598 WINEVENT_OUTOFCONTEXT);
10599 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10600
10601 hevent = CreateEventA(NULL, 0, 0, NULL);
10602 assert(hevent);
10603 hwnd2 = hevent;
10604
10605 flush_sequence();
10606
10607 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10608 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10609
10610 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10611
10612 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10613 /* process pending winevent messages */
10614 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10615 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10616
10617 flush_sequence();
10618 /* this one should be received only by old hook proc */
10619 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10620 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10621 /* this one should be received only by old hook proc */
10622 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10623
10624 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10625 /* process pending winevent messages */
10626 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10627 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10628
10629 ret = pUnhookWinEvent(hhook);
10630 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10631
10632 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10633 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10634 CloseHandle(hthread);
10635 CloseHandle(hevent);
10636 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10637 /****** end of out of context event test *************/
10638
10639 /****** start of MOUSE_LL hook test *************/
10640 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10641 /* WH_MOUSE_LL is not supported on Win9x platforms */
10642 if (!hCBT_global_hook)
10643 {
10644 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10645 goto skip_mouse_ll_hook_test;
10646 }
10647
10648 hevent = CreateEventA(NULL, 0, 0, NULL);
10649 assert(hevent);
10650 hwnd2 = hevent;
10651
10652 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10653 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10654
10655 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10656 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10657
10658 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10659 flush_sequence();
10660
10661 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10662 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10663 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10664
10665 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10666
10667 ret = UnhookWindowsHookEx(hCBT_global_hook);
10668 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10669
10670 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10671 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10672 CloseHandle(hthread);
10673 CloseHandle(hevent);
10674 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10675 /****** end of MOUSE_LL hook test *************/
10676 skip_mouse_ll_hook_test:
10677
10678 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10679 }
10680
10681 static void test_set_hook(void)
10682 {
10683 BOOL ret;
10684 HHOOK hhook;
10685 HWINEVENTHOOK hwinevent_hook;
10686
10687 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10688 ok(hhook != 0, "local hook does not require hModule set to 0\n");
10689 UnhookWindowsHookEx(hhook);
10690
10691 if (0)
10692 {
10693 /* this test doesn't pass under Win9x: BUG! */
10694 SetLastError(0xdeadbeef);
10695 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10696 ok(!hhook, "global hook requires hModule != 0\n");
10697 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10698 }
10699
10700 SetLastError(0xdeadbeef);
10701 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10702 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10703 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10704 GetLastError() == 0xdeadbeef, /* Win9x */
10705 "unexpected error %d\n", GetLastError());
10706
10707 SetLastError(0xdeadbeef);
10708 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10709 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10710 GetLastError() == 0xdeadbeef, /* Win9x */
10711 "unexpected error %d\n", GetLastError());
10712
10713 if (!pSetWinEventHook || !pUnhookWinEvent) return;
10714
10715 /* even process local incontext hooks require hmodule */
10716 SetLastError(0xdeadbeef);
10717 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10718 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10719 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10720 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10721 GetLastError() == 0xdeadbeef, /* Win9x */
10722 "unexpected error %d\n", GetLastError());
10723
10724 /* even thread local incontext hooks require hmodule */
10725 SetLastError(0xdeadbeef);
10726 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10727 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10728 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10729 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10730 GetLastError() == 0xdeadbeef, /* Win9x */
10731 "unexpected error %d\n", GetLastError());
10732
10733 if (0)
10734 {
10735 /* these 3 tests don't pass under Win9x */
10736 SetLastError(0xdeadbeef);
10737 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10738 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10739 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10740 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10741
10742 SetLastError(0xdeadbeef);
10743 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10744 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10745 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10746 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10747
10748 SetLastError(0xdeadbeef);
10749 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10750 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10751 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10752 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10753 }
10754
10755 SetLastError(0xdeadbeef);
10756 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10757 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10758 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10759 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10760 ret = pUnhookWinEvent(hwinevent_hook);
10761 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10762
10763 todo_wine {
10764 /* This call succeeds under win2k SP4, but fails under Wine.
10765 Does win2k test/use passed process id? */
10766 SetLastError(0xdeadbeef);
10767 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10768 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10769 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10770 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10771 ret = pUnhookWinEvent(hwinevent_hook);
10772 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10773 }
10774
10775 SetLastError(0xdeadbeef);
10776 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10777 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10778 GetLastError() == 0xdeadbeef, /* Win9x */
10779 "unexpected error %d\n", GetLastError());
10780 }
10781
10782 static HWND hook_hwnd;
10783 static HHOOK recursive_hook;
10784 static int hook_depth, max_hook_depth;
10785
10786 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
10787 {
10788 LRESULT res;
10789 MSG msg;
10790 BOOL b;
10791
10792 hook_depth++;
10793 if(hook_depth > max_hook_depth)
10794 max_hook_depth = hook_depth;
10795
10796 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
10797 ok(b, "PeekMessage failed\n");
10798
10799 res = CallNextHookEx(recursive_hook, code, w, l);
10800
10801 hook_depth--;
10802 return res;
10803 }
10804
10805 static void test_recursive_hook(void)
10806 {
10807 MSG msg;
10808 BOOL b;
10809
10810 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
10811 ok(hook_hwnd != NULL, "CreateWindow failed\n");
10812
10813 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
10814 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
10815
10816 PostMessageW(hook_hwnd, WM_USER, 0, 0);
10817 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
10818
10819 hook_depth = 0;
10820 GetMessageW(&msg, hook_hwnd, 0, 0);
10821 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
10822 trace("max_hook_depth = %d\n", max_hook_depth);
10823
10824 b = UnhookWindowsHookEx(recursive_hook);
10825 ok(b, "UnhokWindowsHookEx failed\n");
10826
10827 DestroyWindow(hook_hwnd);
10828 }
10829
10830 static const struct message ScrollWindowPaint1[] = {
10831 { WM_PAINT, sent },
10832 { WM_ERASEBKGND, sent|beginpaint },
10833 { WM_GETTEXTLENGTH, sent|optional },
10834 { WM_PAINT, sent|optional },
10835 { WM_NCPAINT, sent|beginpaint|optional },
10836 { WM_GETTEXT, sent|beginpaint|optional },
10837 { WM_GETTEXT, sent|beginpaint|optional },
10838 { WM_GETTEXT, sent|beginpaint|optional },
10839 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
10840 { WM_ERASEBKGND, sent|beginpaint|optional },
10841 { 0 }
10842 };
10843
10844 static const struct message ScrollWindowPaint2[] = {
10845 { WM_PAINT, sent },
10846 { 0 }
10847 };
10848
10849 static void test_scrollwindowex(void)
10850 {
10851 HWND hwnd, hchild;
10852 RECT rect={0,0,130,130};
10853
10854 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
10855 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
10856 100, 100, 200, 200, 0, 0, 0, NULL);
10857 ok (hwnd != 0, "Failed to create overlapped window\n");
10858 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
10859 WS_VISIBLE|WS_CAPTION|WS_CHILD,
10860 10, 10, 150, 150, hwnd, 0, 0, NULL);
10861 ok (hchild != 0, "Failed to create child\n");
10862 UpdateWindow(hwnd);
10863 flush_events();
10864 flush_sequence();
10865
10866 /* scroll without the child window */
10867 trace("start scroll\n");
10868 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10869 SW_ERASE|SW_INVALIDATE);
10870 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10871 trace("end scroll\n");
10872 flush_sequence();
10873 flush_events();
10874 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10875 flush_events();
10876 flush_sequence();
10877
10878 /* Now without the SW_ERASE flag */
10879 trace("start scroll\n");
10880 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
10881 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10882 trace("end scroll\n");
10883 flush_sequence();
10884 flush_events();
10885 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
10886 flush_events();
10887 flush_sequence();
10888
10889 /* now scroll the child window as well */
10890 trace("start scroll\n");
10891 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10892 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
10893 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
10894 /* windows sometimes a WM_MOVE */
10895 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
10896 trace("end scroll\n");
10897 flush_sequence();
10898 flush_events();
10899 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10900 flush_events();
10901 flush_sequence();
10902
10903 /* now scroll with ScrollWindow() */
10904 trace("start scroll with ScrollWindow\n");
10905 ScrollWindow( hwnd, 5, 5, NULL, NULL);
10906 trace("end scroll\n");
10907 flush_sequence();
10908 flush_events();
10909 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
10910
10911 ok(DestroyWindow(hchild), "failed to destroy window\n");
10912 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10913 flush_sequence();
10914 }
10915
10916 static const struct message destroy_window_with_children[] = {
10917 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10918 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
10919 { 0x0090, sent|optional },
10920 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
10921 { 0x0090, sent|optional },
10922 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10923 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10924 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10925 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10926 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
10927 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10928 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10929 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10930 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10931 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10932 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10933 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10934 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10935 { 0 }
10936 };
10937
10938 static void test_DestroyWindow(void)
10939 {
10940 BOOL ret;
10941 HWND parent, child1, child2, child3, child4, test;
10942 UINT_PTR child_id = WND_CHILD_ID + 1;
10943
10944 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10945 100, 100, 200, 200, 0, 0, 0, NULL);
10946 assert(parent != 0);
10947 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10948 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
10949 assert(child1 != 0);
10950 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10951 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
10952 assert(child2 != 0);
10953 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10954 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
10955 assert(child3 != 0);
10956 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
10957 0, 0, 50, 50, parent, 0, 0, NULL);
10958 assert(child4 != 0);
10959
10960 /* test owner/parent of child2 */
10961 test = GetParent(child2);
10962 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10963 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10964 if(pGetAncestor) {
10965 test = pGetAncestor(child2, GA_PARENT);
10966 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10967 }
10968 test = GetWindow(child2, GW_OWNER);
10969 ok(!test, "wrong owner %p\n", test);
10970
10971 test = SetParent(child2, parent);
10972 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
10973
10974 /* test owner/parent of the parent */
10975 test = GetParent(parent);
10976 ok(!test, "wrong parent %p\n", test);
10977 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
10978 if(pGetAncestor) {
10979 test = pGetAncestor(parent, GA_PARENT);
10980 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10981 }
10982 test = GetWindow(parent, GW_OWNER);
10983 ok(!test, "wrong owner %p\n", test);
10984
10985 /* test owner/parent of child1 */
10986 test = GetParent(child1);
10987 ok(test == parent, "wrong parent %p\n", test);
10988 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
10989 if(pGetAncestor) {
10990 test = pGetAncestor(child1, GA_PARENT);
10991 ok(test == parent, "wrong parent %p\n", test);
10992 }
10993 test = GetWindow(child1, GW_OWNER);
10994 ok(!test, "wrong owner %p\n", test);
10995
10996 /* test owner/parent of child2 */
10997 test = GetParent(child2);
10998 ok(test == parent, "wrong parent %p\n", test);
10999 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11000 if(pGetAncestor) {
11001 test = pGetAncestor(child2, GA_PARENT);
11002 ok(test == parent, "wrong parent %p\n", test);
11003 }
11004 test = GetWindow(child2, GW_OWNER);
11005 ok(!test, "wrong owner %p\n", test);
11006
11007 /* test owner/parent of child3 */
11008 test = GetParent(child3);
11009 ok(test == child1, "wrong parent %p\n", test);
11010 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
11011 if(pGetAncestor) {
11012 test = pGetAncestor(child3, GA_PARENT);
11013 ok(test == child1, "wrong parent %p\n", test);
11014 }
11015 test = GetWindow(child3, GW_OWNER);
11016 ok(!test, "wrong owner %p\n", test);
11017
11018 /* test owner/parent of child4 */
11019 test = GetParent(child4);
11020 ok(test == parent, "wrong parent %p\n", test);
11021 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
11022 if(pGetAncestor) {
11023 test = pGetAncestor(child4, GA_PARENT);
11024 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11025 }
11026 test = GetWindow(child4, GW_OWNER);
11027 ok(test == parent, "wrong owner %p\n", test);
11028
11029 flush_sequence();
11030
11031 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
11032 parent, child1, child2, child3, child4);
11033
11034 SetCapture(child4);
11035 test = GetCapture();
11036 ok(test == child4, "wrong capture window %p\n", test);
11037
11038 test_DestroyWindow_flag = TRUE;
11039 ret = DestroyWindow(parent);
11040 ok( ret, "DestroyWindow() error %d\n", GetLastError());
11041 test_DestroyWindow_flag = FALSE;
11042 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
11043
11044 ok(!IsWindow(parent), "parent still exists\n");
11045 ok(!IsWindow(child1), "child1 still exists\n");
11046 ok(!IsWindow(child2), "child2 still exists\n");
11047 ok(!IsWindow(child3), "child3 still exists\n");
11048 ok(!IsWindow(child4), "child4 still exists\n");
11049
11050 test = GetCapture();
11051 ok(!test, "wrong capture window %p\n", test);
11052 }
11053
11054
11055 static const struct message WmDispatchPaint[] = {
11056 { WM_NCPAINT, sent },
11057 { WM_GETTEXT, sent|defwinproc|optional },
11058 { WM_GETTEXT, sent|defwinproc|optional },
11059 { WM_ERASEBKGND, sent },
11060 { 0 }
11061 };
11062
11063 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11064 {
11065 if (message == WM_PAINT) return 0;
11066 return MsgCheckProcA( hwnd, message, wParam, lParam );
11067 }
11068
11069 static void test_DispatchMessage(void)
11070 {
11071 RECT rect;
11072 MSG msg;
11073 int count;
11074 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11075 100, 100, 200, 200, 0, 0, 0, NULL);
11076 ShowWindow( hwnd, SW_SHOW );
11077 UpdateWindow( hwnd );
11078 flush_events();
11079 flush_sequence();
11080 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
11081
11082 SetRect( &rect, -5, -5, 5, 5 );
11083 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11084 count = 0;
11085 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11086 {
11087 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11088 else
11089 {
11090 flush_sequence();
11091 DispatchMessageA( &msg );
11092 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
11093 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11094 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
11095 if (++count > 10) break;
11096 }
11097 }
11098 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
11099
11100 trace("now without DispatchMessage\n");
11101 flush_sequence();
11102 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11103 count = 0;
11104 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11105 {
11106 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11107 else
11108 {
11109 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11110 flush_sequence();
11111 /* this will send WM_NCCPAINT just like DispatchMessage does */
11112 GetUpdateRgn( hwnd, hrgn, TRUE );
11113 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11114 DeleteObject( hrgn );
11115 GetClientRect( hwnd, &rect );
11116 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
11117 ok( !count, "Got multiple WM_PAINTs\n" );
11118 if (++count > 10) break;
11119 }
11120 }
11121
11122 flush_sequence();
11123 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11124 count = 0;
11125 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11126 {
11127 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11128 else
11129 {
11130 HDC hdc;
11131
11132 flush_sequence();
11133 hdc = BeginPaint( hwnd, NULL );
11134 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11135 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11136 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11137 ok( !count, "Got multiple WM_PAINTs\n" );
11138 if (++count > 10) break;
11139 }
11140 }
11141 DestroyWindow(hwnd);
11142 }
11143
11144
11145 static const struct message WmUser[] = {
11146 { WM_USER, sent },
11147 { 0 }
11148 };
11149
11150 struct sendmsg_info
11151 {
11152 HWND hwnd;
11153 DWORD timeout;
11154 DWORD ret;
11155 };
11156
11157 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11158 {
11159 struct sendmsg_info *info = arg;
11160 SetLastError( 0xdeadbeef );
11161 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11162 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11163 broken(GetLastError() == 0), /* win9x */
11164 "unexpected error %d\n", GetLastError());
11165 return 0;
11166 }
11167
11168 static void wait_for_thread( HANDLE thread )
11169 {
11170 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11171 {
11172 MSG msg;
11173 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11174 }
11175 }
11176
11177 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11178 {
11179 if (message == WM_USER) Sleep(200);
11180 return MsgCheckProcA( hwnd, message, wParam, lParam );
11181 }
11182
11183 static void test_SendMessageTimeout(void)
11184 {
11185 HANDLE thread;
11186 struct sendmsg_info info;
11187 DWORD tid;
11188 BOOL is_win9x;
11189
11190 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11191 100, 100, 200, 200, 0, 0, 0, NULL);
11192 flush_events();
11193 flush_sequence();
11194
11195 info.timeout = 1000;
11196 info.ret = 0xdeadbeef;
11197 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11198 wait_for_thread( thread );
11199 CloseHandle( thread );
11200 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11201 ok_sequence( WmUser, "WmUser", FALSE );
11202
11203 info.timeout = 1;
11204 info.ret = 0xdeadbeef;
11205 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11206 Sleep(100); /* SendMessageTimeout should time out here */
11207 wait_for_thread( thread );
11208 CloseHandle( thread );
11209 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11210 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11211
11212 /* 0 means infinite timeout (but not on win9x) */
11213 info.timeout = 0;
11214 info.ret = 0xdeadbeef;
11215 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11216 Sleep(100);
11217 wait_for_thread( thread );
11218 CloseHandle( thread );
11219 is_win9x = !info.ret;
11220 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11221 else ok_sequence( WmUser, "WmUser", FALSE );
11222
11223 /* timeout is treated as signed despite the prototype (but not on win9x) */
11224 info.timeout = 0x7fffffff;
11225 info.ret = 0xdeadbeef;
11226 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11227 Sleep(100);
11228 wait_for_thread( thread );
11229 CloseHandle( thread );
11230 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11231 ok_sequence( WmUser, "WmUser", FALSE );
11232
11233 info.timeout = 0x80000000;
11234 info.ret = 0xdeadbeef;
11235 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11236 Sleep(100);
11237 wait_for_thread( thread );
11238 CloseHandle( thread );
11239 if (is_win9x)
11240 {
11241 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11242 ok_sequence( WmUser, "WmUser", FALSE );
11243 }
11244 else
11245 {
11246 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11247 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11248 }
11249
11250 /* now check for timeout during message processing */
11251 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11252 info.timeout = 100;
11253 info.ret = 0xdeadbeef;
11254 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11255 wait_for_thread( thread );
11256 CloseHandle( thread );
11257 /* we should time out but still get the message */
11258 ok( info.ret == 0, "SendMessageTimeout failed\n" );
11259 ok_sequence( WmUser, "WmUser", FALSE );
11260
11261 DestroyWindow( info.hwnd );
11262 }
11263
11264
11265 /****************** edit message test *************************/
11266 #define ID_EDIT 0x1234
11267 static const struct message sl_edit_setfocus[] =
11268 {
11269 { HCBT_SETFOCUS, hook },
11270 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11271 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11272 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11273 { WM_SETFOCUS, sent|wparam, 0 },
11274 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11275 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11276 { WM_CTLCOLOREDIT, sent|parent },
11277 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11278 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11279 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11280 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11281 { 0 }
11282 };
11283 static const struct message sl_edit_invisible[] =
11284 {
11285 { HCBT_SETFOCUS, hook },
11286 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11287 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11288 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11289 { WM_KILLFOCUS, sent|parent },
11290 { WM_SETFOCUS, sent },
11291 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11292 { 0 }
11293 };
11294 static const struct message ml_edit_setfocus[] =
11295 {
11296 { HCBT_SETFOCUS, hook },
11297 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11298 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11299 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11300 { WM_SETFOCUS, sent|wparam, 0 },
11301 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11302 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11303 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11304 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11305 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11306 { 0 }
11307 };
11308 static const struct message sl_edit_killfocus[] =
11309 {
11310 { HCBT_SETFOCUS, hook },
11311 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11312 { WM_KILLFOCUS, sent|wparam, 0 },
11313 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11314 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11315 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11316 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11317 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11318 { 0 }
11319 };
11320 static const struct message sl_edit_lbutton_dblclk[] =
11321 {
11322 { WM_LBUTTONDBLCLK, sent },
11323 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11324 { 0 }
11325 };
11326 static const struct message sl_edit_lbutton_down[] =
11327 {
11328 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11329 { HCBT_SETFOCUS, hook },
11330 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11331 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11332 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11333 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11334 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11335 { WM_CTLCOLOREDIT, sent|parent },
11336 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11337 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11338 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11339 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11340 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11341 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11342 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11343 { WM_CTLCOLOREDIT, sent|parent|optional },
11344 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11345 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11346 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11347 { 0 }
11348 };
11349 static const struct message ml_edit_lbutton_down[] =
11350 {
11351 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11352 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11353 { HCBT_SETFOCUS, hook },
11354 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11355 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11356 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11357 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11358 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11359 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11360 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11361 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11362 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11363 { 0 }
11364 };
11365 static const struct message sl_edit_lbutton_up[] =
11366 {
11367 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11368 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11369 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11370 { WM_CAPTURECHANGED, sent|defwinproc },
11371 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11372 { 0 }
11373 };
11374 static const struct message ml_edit_lbutton_up[] =
11375 {
11376 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11377 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11378 { WM_CAPTURECHANGED, sent|defwinproc },
11379 { 0 }
11380 };
11381
11382 static WNDPROC old_edit_proc;
11383
11384 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11385 {
11386 static LONG defwndproc_counter = 0;
11387 LRESULT ret;
11388 struct recvd_message msg;
11389
11390 if (ignore_message( message )) return 0;
11391
11392 msg.hwnd = hwnd;
11393 msg.message = message;
11394 msg.flags = sent|wparam|lparam;
11395 if (defwndproc_counter) msg.flags |= defwinproc;
11396 msg.wParam = wParam;
11397 msg.lParam = lParam;
11398 msg.descr = "edit";
11399 add_message(&msg);
11400
11401 defwndproc_counter++;
11402 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11403 defwndproc_counter--;
11404
11405 return ret;
11406 }
11407
11408 static void subclass_edit(void)
11409 {
11410 WNDCLASSA cls;
11411
11412 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11413
11414 old_edit_proc = cls.lpfnWndProc;
11415
11416 cls.hInstance = GetModuleHandleA(NULL);
11417 cls.lpfnWndProc = edit_hook_proc;
11418 cls.lpszClassName = "my_edit_class";
11419 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11420 if (!RegisterClassA(&cls)) assert(0);
11421 }
11422
11423 static void test_edit_messages(void)
11424 {
11425 HWND hwnd, parent;
11426 DWORD dlg_code;
11427
11428 subclass_edit();
11429 log_all_parent_messages++;
11430
11431 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11432 100, 100, 200, 200, 0, 0, 0, NULL);
11433 ok (parent != 0, "Failed to create parent window\n");
11434
11435 /* test single line edit */
11436 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11437 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11438 ok(hwnd != 0, "Failed to create edit window\n");
11439
11440 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11441 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11442
11443 flush_sequence();
11444 SetFocus(hwnd);
11445 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11446
11447 ShowWindow(hwnd, SW_SHOW);
11448 UpdateWindow(hwnd);
11449 SetFocus(0);
11450 flush_sequence();
11451
11452 SetFocus(hwnd);
11453 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11454
11455 SetFocus(0);
11456 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11457
11458 SetFocus(0);
11459 ReleaseCapture();
11460 flush_sequence();
11461
11462 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11463 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11464
11465 SetFocus(0);
11466 ReleaseCapture();
11467 flush_sequence();
11468
11469 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11470 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11471
11472 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11473 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11474
11475 DestroyWindow(hwnd);
11476
11477 /* test multiline edit */
11478 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11479 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11480 ok(hwnd != 0, "Failed to create edit window\n");
11481
11482 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11483 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11484 "wrong dlg_code %08x\n", dlg_code);
11485
11486 ShowWindow(hwnd, SW_SHOW);
11487 UpdateWindow(hwnd);
11488 SetFocus(0);
11489 flush_sequence();
11490
11491 SetFocus(hwnd);
11492 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11493
11494 SetFocus(0);
11495 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11496
11497 SetFocus(0);
11498 ReleaseCapture();
11499 flush_sequence();
11500
11501 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11502 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11503
11504 SetFocus(0);
11505 ReleaseCapture();
11506 flush_sequence();
11507
11508 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11509 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11510
11511 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11512 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11513
11514 DestroyWindow(hwnd);
11515 DestroyWindow(parent);
11516
11517 log_all_parent_messages--;
11518 }
11519
11520 /**************************** End of Edit test ******************************/
11521
11522 static const struct message WmKeyDownSkippedSeq[] =
11523 {
11524 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11525 { 0 }
11526 };
11527 static const struct message WmKeyDownWasDownSkippedSeq[] =
11528 {
11529 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11530 { 0 }
11531 };
11532 static const struct message WmKeyUpSkippedSeq[] =
11533 {
11534 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11535 { 0 }
11536 };
11537 static const struct message WmUserKeyUpSkippedSeq[] =
11538 {
11539 { WM_USER, sent },
11540 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11541 { 0 }
11542 };
11543
11544 #define EV_STOP 0
11545 #define EV_SENDMSG 1
11546 #define EV_ACK 2
11547
11548 struct peekmsg_info
11549 {
11550 HWND hwnd;
11551 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11552 };
11553
11554 static DWORD CALLBACK send_msg_thread_2(void *param)
11555 {
11556 DWORD ret;
11557 struct peekmsg_info *info = param;
11558
11559 trace("thread: looping\n");
11560 SetEvent(info->hevent[EV_ACK]);
11561
11562 while (1)
11563 {
11564 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
11565
11566 switch (ret)
11567 {
11568 case WAIT_OBJECT_0 + EV_STOP:
11569 trace("thread: exiting\n");
11570 return 0;
11571
11572 case WAIT_OBJECT_0 + EV_SENDMSG:
11573 trace("thread: sending message\n");
11574 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11575 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11576 SetEvent(info->hevent[EV_ACK]);
11577 break;
11578
11579 default:
11580 trace("unexpected return: %04x\n", ret);
11581 assert(0);
11582 break;
11583 }
11584 }
11585 return 0;
11586 }
11587
11588 static void test_PeekMessage(void)
11589 {
11590 MSG msg;
11591 HANDLE hthread;
11592 DWORD tid, qstatus;
11593 UINT qs_all_input = QS_ALLINPUT;
11594 UINT qs_input = QS_INPUT;
11595 BOOL ret;
11596 struct peekmsg_info info;
11597
11598 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11599 100, 100, 200, 200, 0, 0, 0, NULL);
11600 assert(info.hwnd);
11601 ShowWindow(info.hwnd, SW_SHOW);
11602 UpdateWindow(info.hwnd);
11603 SetFocus(info.hwnd);
11604
11605 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11606 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11607 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11608
11609 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11610 WaitForSingleObject(info.hevent[EV_ACK], 10000);
11611
11612 flush_events();
11613 flush_sequence();
11614
11615 SetLastError(0xdeadbeef);
11616 qstatus = GetQueueStatus(qs_all_input);
11617 if (GetLastError() == ERROR_INVALID_FLAGS)
11618 {
11619 trace("QS_RAWINPUT not supported on this platform\n");
11620 qs_all_input &= ~QS_RAWINPUT;
11621 qs_input &= ~QS_RAWINPUT;
11622 }
11623 if (qstatus & QS_POSTMESSAGE)
11624 {
11625 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11626 qstatus = GetQueueStatus(qs_all_input);
11627 }
11628 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11629
11630 trace("signalling to send message\n");
11631 SetEvent(info.hevent[EV_SENDMSG]);
11632 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11633
11634 /* pass invalid QS_xxxx flags */
11635 SetLastError(0xdeadbeef);
11636 qstatus = GetQueueStatus(0xffffffff);
11637 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11638 if (!qstatus)
11639 {
11640 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11641 qstatus = GetQueueStatus(qs_all_input);
11642 }
11643 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
11644 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11645 "wrong qstatus %08x\n", qstatus);
11646
11647 msg.message = 0;
11648 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11649 ok(!ret,
11650 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11651 msg.message);
11652 ok_sequence(WmUser, "WmUser", FALSE);
11653
11654 qstatus = GetQueueStatus(qs_all_input);
11655 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11656
11657 keybd_event('N', 0, 0, 0);
11658 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11659 qstatus = GetQueueStatus(qs_all_input);
11660 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11661 {
11662 skip( "queuing key events not supported\n" );
11663 goto done;
11664 }
11665 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11666 /* keybd_event seems to trigger a sent message on NT4 */
11667 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11668 "wrong qstatus %08x\n", qstatus);
11669
11670 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11671 qstatus = GetQueueStatus(qs_all_input);
11672 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11673 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11674 "wrong qstatus %08x\n", qstatus);
11675
11676 InvalidateRect(info.hwnd, NULL, FALSE);
11677 qstatus = GetQueueStatus(qs_all_input);
11678 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11679 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11680 "wrong qstatus %08x\n", qstatus);
11681
11682 trace("signalling to send message\n");
11683 SetEvent(info.hevent[EV_SENDMSG]);
11684 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11685
11686 qstatus = GetQueueStatus(qs_all_input);
11687 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11688 "wrong qstatus %08x\n", qstatus);
11689
11690 msg.message = 0;
11691 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11692 if (ret && msg.message == WM_CHAR)
11693 {
11694 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11695 goto done;
11696 }
11697 ok(!ret,
11698 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11699 msg.message);
11700 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
11701 {
11702 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11703 goto done;
11704 }
11705 ok_sequence(WmUser, "WmUser", FALSE);
11706
11707 qstatus = GetQueueStatus(qs_all_input);
11708 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11709 "wrong qstatus %08x\n", qstatus);
11710
11711 trace("signalling to send message\n");
11712 SetEvent(info.hevent[EV_SENDMSG]);
11713 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11714
11715 qstatus = GetQueueStatus(qs_all_input);
11716 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11717 "wrong qstatus %08x\n", qstatus);
11718
11719 msg.message = 0;
11720 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11721 ok(!ret,
11722 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11723 msg.message);
11724 ok_sequence(WmUser, "WmUser", FALSE);
11725
11726 qstatus = GetQueueStatus(qs_all_input);
11727 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11728 "wrong qstatus %08x\n", qstatus);
11729
11730 msg.message = 0;
11731 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11732 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11733 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11734 ret, msg.message, msg.wParam);
11735 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11736
11737 qstatus = GetQueueStatus(qs_all_input);
11738 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11739 "wrong qstatus %08x\n", qstatus);
11740
11741 msg.message = 0;
11742 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11743 ok(!ret,
11744 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11745 msg.message);
11746 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11747
11748 qstatus = GetQueueStatus(qs_all_input);
11749 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11750 "wrong qstatus %08x\n", qstatus);
11751
11752 msg.message = 0;
11753 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11754 ok(ret && msg.message == WM_PAINT,
11755 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11756 DispatchMessageA(&msg);
11757 ok_sequence(WmPaint, "WmPaint", FALSE);
11758
11759 qstatus = GetQueueStatus(qs_all_input);
11760 ok(qstatus == MAKELONG(0, QS_KEY),
11761 "wrong qstatus %08x\n", qstatus);
11762
11763 msg.message = 0;
11764 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11765 ok(!ret,
11766 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11767 msg.message);
11768 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11769
11770 qstatus = GetQueueStatus(qs_all_input);
11771 ok(qstatus == MAKELONG(0, QS_KEY),
11772 "wrong qstatus %08x\n", qstatus);
11773
11774 trace("signalling to send message\n");
11775 SetEvent(info.hevent[EV_SENDMSG]);
11776 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11777
11778 qstatus = GetQueueStatus(qs_all_input);
11779 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11780 "wrong qstatus %08x\n", qstatus);
11781
11782 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11783
11784 qstatus = GetQueueStatus(qs_all_input);
11785 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11786 "wrong qstatus %08x\n", qstatus);
11787
11788 msg.message = 0;
11789 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11790 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11791 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11792 ret, msg.message, msg.wParam);
11793 ok_sequence(WmUser, "WmUser", FALSE);
11794
11795 qstatus = GetQueueStatus(qs_all_input);
11796 ok(qstatus == MAKELONG(0, QS_KEY),
11797 "wrong qstatus %08x\n", qstatus);
11798
11799 msg.message = 0;
11800 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11801 ok(!ret,
11802 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11803 msg.message);
11804 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11805
11806 qstatus = GetQueueStatus(qs_all_input);
11807 ok(qstatus == MAKELONG(0, QS_KEY),
11808 "wrong qstatus %08x\n", qstatus);
11809
11810 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11811
11812 qstatus = GetQueueStatus(qs_all_input);
11813 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
11814 "wrong qstatus %08x\n", qstatus);
11815
11816 trace("signalling to send message\n");
11817 SetEvent(info.hevent[EV_SENDMSG]);
11818 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11819
11820 qstatus = GetQueueStatus(qs_all_input);
11821 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11822 "wrong qstatus %08x\n", qstatus);
11823
11824 msg.message = 0;
11825 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
11826 ok(!ret,
11827 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11828 msg.message);
11829 ok_sequence(WmUser, "WmUser", FALSE);
11830
11831 qstatus = GetQueueStatus(qs_all_input);
11832 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11833 "wrong qstatus %08x\n", qstatus);
11834
11835 msg.message = 0;
11836 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11837 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11838 else /* workaround for a missing QS_RAWINPUT support */
11839 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
11840 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11841 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11842 ret, msg.message, msg.wParam);
11843 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11844
11845 qstatus = GetQueueStatus(qs_all_input);
11846 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11847 "wrong qstatus %08x\n", qstatus);
11848
11849 msg.message = 0;
11850 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11851 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11852 else /* workaround for a missing QS_RAWINPUT support */
11853 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
11854 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11855 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
11856 ret, msg.message, msg.wParam);
11857 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
11858
11859 qstatus = GetQueueStatus(qs_all_input);
11860 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11861 "wrong qstatus %08x\n", qstatus);
11862
11863 msg.message = 0;
11864 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
11865 ok(!ret,
11866 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11867 msg.message);
11868 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11869
11870 qstatus = GetQueueStatus(qs_all_input);
11871 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11872 "wrong qstatus %08x\n", qstatus);
11873
11874 msg.message = 0;
11875 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11876 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11877 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11878 ret, msg.message, msg.wParam);
11879 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11880
11881 qstatus = GetQueueStatus(qs_all_input);
11882 ok(qstatus == 0,
11883 "wrong qstatus %08x\n", qstatus);
11884
11885 msg.message = 0;
11886 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11887 ok(!ret,
11888 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11889 msg.message);
11890 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11891
11892 qstatus = GetQueueStatus(qs_all_input);
11893 ok(qstatus == 0,
11894 "wrong qstatus %08x\n", qstatus);
11895
11896 /* test whether presence of the quit flag in the queue affects
11897 * the queue state
11898 */
11899 PostQuitMessage(0x1234abcd);
11900
11901 qstatus = GetQueueStatus(qs_all_input);
11902 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11903 "wrong qstatus %08x\n", qstatus);
11904
11905 PostMessageA(info.hwnd, WM_USER, 0, 0);
11906
11907 qstatus = GetQueueStatus(qs_all_input);
11908 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11909 "wrong qstatus %08x\n", qstatus);
11910
11911 msg.message = 0;
11912 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11913 ok(ret && msg.message == WM_USER,
11914 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
11915 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11916
11917 qstatus = GetQueueStatus(qs_all_input);
11918 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11919 "wrong qstatus %08x\n", qstatus);
11920
11921 msg.message = 0;
11922 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11923 ok(ret && msg.message == WM_QUIT,
11924 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
11925 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
11926 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
11927 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11928
11929 qstatus = GetQueueStatus(qs_all_input);
11930 todo_wine {
11931 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11932 "wrong qstatus %08x\n", qstatus);
11933 }
11934
11935 msg.message = 0;
11936 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11937 ok(!ret,
11938 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11939 msg.message);
11940 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11941
11942 qstatus = GetQueueStatus(qs_all_input);
11943 ok(qstatus == 0,
11944 "wrong qstatus %08x\n", qstatus);
11945
11946 /* some GetMessage tests */
11947
11948 keybd_event('N', 0, 0, 0);
11949 qstatus = GetQueueStatus(qs_all_input);
11950 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11951
11952 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11953 qstatus = GetQueueStatus(qs_all_input);
11954 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11955
11956 if (qstatus)
11957 {
11958 ret = GetMessageA( &msg, 0, 0, 0 );
11959 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11960 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11961 ret, msg.message, msg.wParam);
11962 qstatus = GetQueueStatus(qs_all_input);
11963 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
11964 }
11965
11966 if (qstatus)
11967 {
11968 ret = GetMessageA( &msg, 0, 0, 0 );
11969 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11970 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11971 ret, msg.message, msg.wParam);
11972 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11973 qstatus = GetQueueStatus(qs_all_input);
11974 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11975 }
11976
11977 keybd_event('N', 0, 0, 0);
11978 qstatus = GetQueueStatus(qs_all_input);
11979 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11980
11981 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11982 qstatus = GetQueueStatus(qs_all_input);
11983 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11984
11985 if (qstatus & (QS_KEY << 16))
11986 {
11987 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11988 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11989 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11990 ret, msg.message, msg.wParam);
11991 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
11992 qstatus = GetQueueStatus(qs_all_input);
11993 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11994 }
11995
11996 if (qstatus)
11997 {
11998 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11999 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12000 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12001 ret, msg.message, msg.wParam);
12002 qstatus = GetQueueStatus(qs_all_input);
12003 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12004 }
12005
12006 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12007 qstatus = GetQueueStatus(qs_all_input);
12008 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12009
12010 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12011 qstatus = GetQueueStatus(qs_all_input);
12012 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12013
12014 trace("signalling to send message\n");
12015 SetEvent(info.hevent[EV_SENDMSG]);
12016 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12017 qstatus = GetQueueStatus(qs_all_input);
12018 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12019 "wrong qstatus %08x\n", qstatus);
12020
12021 if (qstatus & (QS_KEY << 16))
12022 {
12023 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12024 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12025 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12026 ret, msg.message, msg.wParam);
12027 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
12028 qstatus = GetQueueStatus(qs_all_input);
12029 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12030 }
12031
12032 if (qstatus)
12033 {
12034 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12035 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12036 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12037 ret, msg.message, msg.wParam);
12038 qstatus = GetQueueStatus(qs_all_input);
12039 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12040 }
12041 done:
12042 trace("signalling to exit\n");
12043 SetEvent(info.hevent[EV_STOP]);
12044
12045 WaitForSingleObject(hthread, INFINITE);
12046
12047 CloseHandle(hthread);
12048 CloseHandle(info.hevent[0]);
12049 CloseHandle(info.hevent[1]);
12050 CloseHandle(info.hevent[2]);
12051
12052 DestroyWindow(info.hwnd);
12053 }
12054
12055 static void wait_move_event(HWND hwnd, int x, int y)
12056 {
12057 MSG msg;
12058 DWORD time;
12059 BOOL ret;
12060
12061 time = GetTickCount();
12062 while (GetTickCount() - time < 200) {
12063 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12064 if (ret && msg.pt.x > x && msg.pt.y > y) break;
12065 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
12066 else Sleep( GetTickCount() - time );
12067 }
12068 }
12069
12070 #define STEP 5
12071 static void test_PeekMessage2(void)
12072 {
12073 HWND hwnd;
12074 BOOL ret;
12075 MSG msg;
12076 UINT message;
12077 DWORD time1, time2, time3;
12078 int x1, y1, x2, y2, x3, y3;
12079 POINT pos;
12080
12081 time1 = time2 = time3 = 0;
12082 x1 = y1 = x2 = y2 = x3 = y3 = 0;
12083
12084 /* Initialise window and make sure it is ready for events */
12085 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
12086 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12087 assert(hwnd);
12088 trace("Window for test_PeekMessage2 %p\n", hwnd);
12089 ShowWindow(hwnd, SW_SHOW);
12090 UpdateWindow(hwnd);
12091 SetFocus(hwnd);
12092 GetCursorPos(&pos);
12093 SetCursorPos(100, 100);
12094 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
12095 flush_events();
12096
12097 /* Do initial mousemove, wait until we can see it
12098 and then do our test peek with PM_NOREMOVE. */
12099 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12100 wait_move_event(hwnd, 100-STEP, 100-STEP);
12101
12102 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12103 if (!ret)
12104 {
12105 skip( "queuing mouse events not supported\n" );
12106 goto done;
12107 }
12108 else
12109 {
12110 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12111 message = msg.message;
12112 time1 = msg.time;
12113 x1 = msg.pt.x;
12114 y1 = msg.pt.y;
12115 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12116 }
12117
12118 /* Allow time to advance a bit, and then simulate the user moving their
12119 * mouse around. After that we peek again with PM_NOREMOVE.
12120 * Although the previous mousemove message was never removed, the
12121 * mousemove we now peek should reflect the recent mouse movements
12122 * because the input queue will merge the move events. */
12123 Sleep(100);
12124 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12125 wait_move_event(hwnd, x1, y1);
12126
12127 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12128 ok(ret, "no message available\n");
12129 if (ret) {
12130 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12131 message = msg.message;
12132 time2 = msg.time;
12133 x2 = msg.pt.x;
12134 y2 = msg.pt.y;
12135 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12136 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12137 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12138 }
12139
12140 /* Have another go, to drive the point home */
12141 Sleep(100);
12142 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12143 wait_move_event(hwnd, x2, y2);
12144
12145 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12146 ok(ret, "no message available\n");
12147 if (ret) {
12148 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12149 message = msg.message;
12150 time3 = msg.time;
12151 x3 = msg.pt.x;
12152 y3 = msg.pt.y;
12153 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12154 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12155 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12156 }
12157
12158 done:
12159 DestroyWindow(hwnd);
12160 SetCursorPos(pos.x, pos.y);
12161 flush_events();
12162 }
12163
12164 static void test_PeekMessage3(void)
12165 {
12166 HWND hwnd;
12167 BOOL ret;
12168 MSG msg;
12169
12170 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12171 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12172 ok(hwnd != NULL, "expected hwnd != NULL\n");
12173 flush_events();
12174
12175 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12176 * were already seen. */
12177
12178 SetTimer(hwnd, 1, 0, NULL);
12179 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12180 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12181 PostMessageA(hwnd, WM_USER, 0, 0);
12182 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12183 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12184 ret = GetMessageA(&msg, NULL, 0, 0);
12185 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12186 ret = GetMessageA(&msg, NULL, 0, 0);
12187 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12188 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12189 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12190
12191 SetTimer(hwnd, 1, 0, NULL);
12192 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12193 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12194 PostMessageA(hwnd, WM_USER, 0, 0);
12195 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12196 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12197 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12198 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12199 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12200 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12201
12202 /* It doesn't matter if a message range is specified or not. */
12203
12204 SetTimer(hwnd, 1, 0, NULL);
12205 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12206 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12207 PostMessageA(hwnd, WM_USER, 0, 0);
12208 ret = GetMessageA(&msg, NULL, 0, 0);
12209 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12210 ret = GetMessageA(&msg, NULL, 0, 0);
12211 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12212 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12213 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12214
12215 /* But not if the post messages were added before the PeekMessage() call. */
12216
12217 PostMessageA(hwnd, WM_USER, 0, 0);
12218 SetTimer(hwnd, 1, 0, NULL);
12219 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12220 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12221 ret = GetMessageA(&msg, NULL, 0, 0);
12222 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12223 ret = GetMessageA(&msg, NULL, 0, 0);
12224 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12225 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12226 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12227
12228 /* More complicated test with multiple messages. */
12229
12230 PostMessageA(hwnd, WM_USER, 0, 0);
12231 SetTimer(hwnd, 1, 0, NULL);
12232 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12233 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12234 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12235 ret = GetMessageA(&msg, NULL, 0, 0);
12236 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12237 ret = GetMessageA(&msg, NULL, 0, 0);
12238 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12239 ret = GetMessageA(&msg, NULL, 0, 0);
12240 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12241 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12242 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12243
12244 /* Newer messages are still returned when specifying a message range. */
12245
12246 SetTimer(hwnd, 1, 0, NULL);
12247 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12248 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12249 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12250 PostMessageA(hwnd, WM_USER, 0, 0);
12251 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
12252 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12253 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE);
12254 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12255 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12256 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12257 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12258 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12259 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12260 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12261 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12262 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12263
12264 /* Also works for posted messages, but the situation is a bit different,
12265 * because both messages are in the same queue. */
12266
12267 PostMessageA(hwnd, WM_TIMER, 0, 0);
12268 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12269 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12270 PostMessageA(hwnd, WM_USER, 0, 0);
12271 ret = GetMessageA(&msg, NULL, 0, 0);
12272 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12273 ret = GetMessageA(&msg, NULL, 0, 0);
12274 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12275 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12276 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12277
12278 PostMessageA(hwnd, WM_USER, 0, 0);
12279 PostMessageA(hwnd, WM_TIMER, 0, 0);
12280 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12281 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12282 ret = GetMessageA(&msg, NULL, 0, 0);
12283 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12284 ret = GetMessageA(&msg, NULL, 0, 0);
12285 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12286 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12287 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12288
12289 DestroyWindow(hwnd);
12290 flush_events();
12291 }
12292
12293 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12294 {
12295 struct recvd_message msg;
12296
12297 if (ignore_message( message )) return 0;
12298
12299 msg.hwnd = hwnd;
12300 msg.message = message;
12301 msg.flags = sent|wparam|lparam;
12302 msg.wParam = wp;
12303 msg.lParam = lp;
12304 msg.descr = "dialog";
12305 add_message(&msg);
12306
12307 switch (message)
12308 {
12309 case WM_INITDIALOG:
12310 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12311 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12312 return 0;
12313
12314 case WM_GETDLGCODE:
12315 return 0;
12316
12317 case WM_USER:
12318 EndDialog(hwnd, 0);
12319 break;
12320 }
12321
12322 return 1;
12323 }
12324
12325 static const struct message WmQuitDialogSeq[] = {
12326 { HCBT_CREATEWND, hook },
12327 { WM_SETFONT, sent },
12328 { WM_INITDIALOG, sent },
12329 { WM_CHANGEUISTATE, sent|optional },
12330 { HCBT_DESTROYWND, hook },
12331 { 0x0090, sent|optional }, /* Vista */
12332 { WM_DESTROY, sent },
12333 { WM_NCDESTROY, sent },
12334 { 0 }
12335 };
12336
12337 static const struct message WmStopQuitSeq[] = {
12338 { WM_DWMNCRENDERINGCHANGED, posted|optional },
12339 { WM_CLOSE, posted },
12340 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12341 { 0 }
12342 };
12343
12344 static void test_quit_message(void)
12345 {
12346 MSG msg;
12347 BOOL ret;
12348
12349 /* test using PostQuitMessage */
12350 flush_events();
12351 PostQuitMessage(0xbeef);
12352
12353 msg.message = 0;
12354 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12355 ok(!ret, "got %x message\n", msg.message);
12356
12357 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12358 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12359 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12360 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12361
12362 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12363 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12364
12365 ret = GetMessageA(&msg, NULL, 0, 0);
12366 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12367 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12368
12369 /* note: WM_QUIT message received after WM_USER message */
12370 ret = GetMessageA(&msg, NULL, 0, 0);
12371 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12372 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12373 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12374
12375 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12376 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12377
12378 /* now test with PostThreadMessage - different behaviour! */
12379 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12380
12381 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12382 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12383 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12384 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12385
12386 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12387 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12388
12389 /* note: we receive the WM_QUIT message first this time */
12390 ret = GetMessageA(&msg, NULL, 0, 0);
12391 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12392 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12393 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12394
12395 ret = GetMessageA(&msg, NULL, 0, 0);
12396 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12397 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12398
12399 flush_events();
12400 flush_sequence();
12401 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12402 ok(ret == 1, "expected 1, got %d\n", ret);
12403 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12404 memset(&msg, 0xab, sizeof(msg));
12405 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12406 ok(ret, "PeekMessage failed\n");
12407 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12408 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12409 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12410
12411 /* Check what happens to a WM_QUIT message posted to a window that gets
12412 * destroyed.
12413 */
12414 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12415 0, 0, 100, 100, NULL, NULL, NULL, NULL);
12416 flush_sequence();
12417 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12418 {
12419 struct recvd_message rmsg;
12420 rmsg.hwnd = msg.hwnd;
12421 rmsg.message = msg.message;
12422 rmsg.flags = posted|wparam|lparam;
12423 rmsg.wParam = msg.wParam;
12424 rmsg.lParam = msg.lParam;
12425 rmsg.descr = "stop/quit";
12426 if (msg.message == WM_QUIT)
12427 /* The hwnd can only be checked here */
12428 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12429 add_message(&rmsg);
12430 DispatchMessageA(&msg);
12431 }
12432 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12433 }
12434
12435 static const struct message WmNotifySeq[] = {
12436 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12437 { 0 }
12438 };
12439
12440 static void test_notify_message(void)
12441 {
12442 HWND hwnd;
12443 BOOL ret;
12444 MSG msg;
12445
12446 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12447 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12448 ok(hwnd != 0, "Failed to create window\n");
12449 flush_events();
12450 flush_sequence();
12451
12452 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12453 ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12454 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12455
12456 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12457 ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12458 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12459
12460 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12461 ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12462 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12463
12464 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12465 ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12466 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12467
12468 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12469 ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12470 flush_events();
12471 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12472
12473 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12474 ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12475 flush_events();
12476 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12477
12478 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12479 ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12480 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12481 {
12482 msg.hwnd = hwnd;
12483 DispatchMessageA(&msg);
12484 }
12485 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12486
12487 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12488 ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12489 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12490 {
12491 msg.hwnd = hwnd;
12492 DispatchMessageA(&msg);
12493 }
12494 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12495
12496 DestroyWindow(hwnd);
12497 }
12498
12499 static const struct message WmMouseHoverSeq[] = {
12500 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12501 { WM_MOUSEACTIVATE, sent|optional },
12502 { WM_TIMER, sent|optional }, /* XP sends it */
12503 { WM_SYSTIMER, sent },
12504 { WM_MOUSEHOVER, sent|wparam, 0 },
12505 { 0 }
12506 };
12507
12508 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12509 {
12510 MSG msg;
12511 DWORD start_ticks, end_ticks;
12512
12513 start_ticks = GetTickCount();
12514 /* add some deviation (50%) to cover not expected delays */
12515 start_ticks += timeout / 2;
12516
12517 do
12518 {
12519 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12520 {
12521 /* Timer proc messages are not dispatched to the window proc,
12522 * and therefore not logged.
12523 */
12524 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12525 {
12526 struct recvd_message s_msg;
12527
12528 s_msg.hwnd = msg.hwnd;
12529 s_msg.message = msg.message;
12530 s_msg.flags = sent|wparam|lparam;
12531 s_msg.wParam = msg.wParam;
12532 s_msg.lParam = msg.lParam;
12533 s_msg.descr = "msg_loop";
12534 add_message(&s_msg);
12535 }
12536 DispatchMessageA(&msg);
12537 }
12538
12539 end_ticks = GetTickCount();
12540
12541 /* inject WM_MOUSEMOVE to see how it changes tracking */
12542 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
12543 {
12544 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12545 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12546
12547 inject_mouse_move = FALSE;
12548 }
12549 } while (start_ticks + timeout >= end_ticks);
12550 }
12551
12552 static void test_TrackMouseEvent(void)
12553 {
12554 TRACKMOUSEEVENT tme;
12555 BOOL ret;
12556 HWND hwnd, hchild;
12557 RECT rc_parent, rc_child;
12558 UINT default_hover_time, hover_width = 0, hover_height = 0;
12559
12560 #define track_hover(track_hwnd, track_hover_time) \
12561 tme.cbSize = sizeof(tme); \
12562 tme.dwFlags = TME_HOVER; \
12563 tme.hwndTrack = track_hwnd; \
12564 tme.dwHoverTime = track_hover_time; \
12565 SetLastError(0xdeadbeef); \
12566 ret = pTrackMouseEvent(&tme); \
12567 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
12568
12569 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
12570 tme.cbSize = sizeof(tme); \
12571 tme.dwFlags = TME_QUERY; \
12572 tme.hwndTrack = (HWND)0xdeadbeef; \
12573 tme.dwHoverTime = 0xdeadbeef; \
12574 SetLastError(0xdeadbeef); \
12575 ret = pTrackMouseEvent(&tme); \
12576 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
12577 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
12578 ok(tme.dwFlags == (expected_track_flags), \
12579 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
12580 ok(tme.hwndTrack == (expected_track_hwnd), \
12581 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
12582 ok(tme.dwHoverTime == (expected_hover_time), \
12583 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
12584
12585 #define track_hover_cancel(track_hwnd) \
12586 tme.cbSize = sizeof(tme); \
12587 tme.dwFlags = TME_HOVER | TME_CANCEL; \
12588 tme.hwndTrack = track_hwnd; \
12589 tme.dwHoverTime = 0xdeadbeef; \
12590 SetLastError(0xdeadbeef); \
12591 ret = pTrackMouseEvent(&tme); \
12592 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12593
12594 default_hover_time = 0xdeadbeef;
12595 SetLastError(0xdeadbeef);
12596 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12597 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12598 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12599 if (!ret) default_hover_time = 400;
12600 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12601
12602 SetLastError(0xdeadbeef);
12603 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12604 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12605 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12606 if (!ret) hover_width = 4;
12607 SetLastError(0xdeadbeef);
12608 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12609 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12610 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12611 if (!ret) hover_height = 4;
12612 trace("hover rect is %u x %d\n", hover_width, hover_height);
12613
12614 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12615 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12616 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12617 NULL, NULL, 0);
12618 assert(hwnd);
12619
12620 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12621 WS_CHILD | WS_BORDER | WS_VISIBLE,
12622 50, 50, 200, 200, hwnd,
12623 NULL, NULL, 0);
12624 assert(hchild);
12625
12626 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12627 flush_events();
12628 flush_sequence();
12629
12630 tme.cbSize = 0;
12631 tme.dwFlags = TME_QUERY;
12632 tme.hwndTrack = (HWND)0xdeadbeef;
12633 tme.dwHoverTime = 0xdeadbeef;
12634 SetLastError(0xdeadbeef);
12635 ret = pTrackMouseEvent(&tme);
12636 ok(!ret, "TrackMouseEvent should fail\n");
12637 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12638 "not expected error %u\n", GetLastError());
12639
12640 tme.cbSize = sizeof(tme);
12641 tme.dwFlags = TME_HOVER;
12642 tme.hwndTrack = (HWND)0xdeadbeef;
12643 tme.dwHoverTime = 0xdeadbeef;
12644 SetLastError(0xdeadbeef);
12645 ret = pTrackMouseEvent(&tme);
12646 ok(!ret, "TrackMouseEvent should fail\n");
12647 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12648 "not expected error %u\n", GetLastError());
12649
12650 tme.cbSize = sizeof(tme);
12651 tme.dwFlags = TME_HOVER | TME_CANCEL;
12652 tme.hwndTrack = (HWND)0xdeadbeef;
12653 tme.dwHoverTime = 0xdeadbeef;
12654 SetLastError(0xdeadbeef);
12655 ret = pTrackMouseEvent(&tme);
12656 ok(!ret, "TrackMouseEvent should fail\n");
12657 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12658 "not expected error %u\n", GetLastError());
12659
12660 GetWindowRect(hwnd, &rc_parent);
12661 GetWindowRect(hchild, &rc_child);
12662 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12663
12664 /* Process messages so that the system updates its internal current
12665 * window and hittest, otherwise TrackMouseEvent calls don't have any
12666 * effect.
12667 */
12668 flush_events();
12669 flush_sequence();
12670
12671 track_query(0, NULL, 0);
12672 track_hover(hchild, 0);
12673 track_query(0, NULL, 0);
12674
12675 flush_events();
12676 flush_sequence();
12677
12678 track_hover(hwnd, 0);
12679 tme.cbSize = sizeof(tme);
12680 tme.dwFlags = TME_QUERY;
12681 tme.hwndTrack = (HWND)0xdeadbeef;
12682 tme.dwHoverTime = 0xdeadbeef;
12683 SetLastError(0xdeadbeef);
12684 ret = pTrackMouseEvent(&tme);
12685 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12686 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12687 if (!tme.dwFlags)
12688 {
12689 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12690 DestroyWindow( hwnd );
12691 return;
12692 }
12693 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12694 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12695 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12696 tme.dwHoverTime, default_hover_time);
12697
12698 pump_msg_loop_timeout(default_hover_time, FALSE);
12699 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12700
12701 track_query(0, NULL, 0);
12702
12703 track_hover(hwnd, HOVER_DEFAULT);
12704 track_query(TME_HOVER, hwnd, default_hover_time);
12705
12706 Sleep(default_hover_time / 2);
12707 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12708 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12709
12710 track_query(TME_HOVER, hwnd, default_hover_time);
12711
12712 pump_msg_loop_timeout(default_hover_time, FALSE);
12713 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12714
12715 track_query(0, NULL, 0);
12716
12717 track_hover(hwnd, HOVER_DEFAULT);
12718 track_query(TME_HOVER, hwnd, default_hover_time);
12719
12720 pump_msg_loop_timeout(default_hover_time, TRUE);
12721 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12722
12723 track_query(0, NULL, 0);
12724
12725 track_hover(hwnd, HOVER_DEFAULT);
12726 track_query(TME_HOVER, hwnd, default_hover_time);
12727 track_hover_cancel(hwnd);
12728
12729 DestroyWindow(hwnd);
12730
12731 #undef track_hover
12732 #undef track_query
12733 #undef track_hover_cancel
12734 }
12735
12736
12737 static const struct message WmSetWindowRgn[] = {
12738 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12739 { WM_NCCALCSIZE, sent|wparam, 1 },
12740 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12741 { WM_GETTEXT, sent|defwinproc|optional },
12742 { WM_ERASEBKGND, sent|optional },
12743 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12744 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12745 { 0 }
12746 };
12747
12748 static const struct message WmSetWindowRgn_no_redraw[] = {
12749 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12750 { WM_NCCALCSIZE, sent|wparam, 1 },
12751 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12752 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12753 { 0 }
12754 };
12755
12756 static const struct message WmSetWindowRgn_clear[] = {
12757 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12758 { WM_NCCALCSIZE, sent|wparam, 1 },
12759 { WM_NCPAINT, sent|optional },
12760 { WM_GETTEXT, sent|defwinproc|optional },
12761 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
12762 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12763 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
12764 { WM_NCPAINT, sent|optional },
12765 { WM_GETTEXT, sent|defwinproc|optional },
12766 { WM_ERASEBKGND, sent|optional },
12767 { WM_WINDOWPOSCHANGING, sent|optional },
12768 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12769 { WM_NCPAINT, sent|optional },
12770 { WM_GETTEXT, sent|defwinproc|optional },
12771 { WM_ERASEBKGND, sent|optional },
12772 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12773 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12774 { WM_NCPAINT, sent|optional },
12775 { WM_GETTEXT, sent|defwinproc|optional },
12776 { WM_ERASEBKGND, sent|optional },
12777 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12778 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12779 { 0 }
12780 };
12781
12782 static void test_SetWindowRgn(void)
12783 {
12784 HRGN hrgn;
12785 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
12786 100, 100, 200, 200, 0, 0, 0, NULL);
12787 ok( hwnd != 0, "Failed to create overlapped window\n" );
12788
12789 ShowWindow( hwnd, SW_SHOW );
12790 UpdateWindow( hwnd );
12791 flush_events();
12792 flush_sequence();
12793
12794 trace("testing SetWindowRgn\n");
12795 hrgn = CreateRectRgn( 0, 0, 150, 150 );
12796 SetWindowRgn( hwnd, hrgn, TRUE );
12797 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
12798
12799 hrgn = CreateRectRgn( 30, 30, 160, 160 );
12800 SetWindowRgn( hwnd, hrgn, FALSE );
12801 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
12802
12803 hrgn = CreateRectRgn( 0, 0, 180, 180 );
12804 SetWindowRgn( hwnd, hrgn, TRUE );
12805 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
12806
12807 SetWindowRgn( hwnd, 0, TRUE );
12808 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
12809
12810 DestroyWindow( hwnd );
12811 }
12812
12813 /*************************** ShowWindow() test ******************************/
12814 static const struct message WmShowNormal[] = {
12815 { WM_SHOWWINDOW, sent|wparam, 1 },
12816 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12817 { HCBT_ACTIVATE, hook },
12818 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12819 { HCBT_SETFOCUS, hook },
12820 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12821 { 0 }
12822 };
12823 static const struct message WmShow[] = {
12824 { WM_SHOWWINDOW, sent|wparam, 1 },
12825 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12826 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12827 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12828 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12829 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12830 { 0 }
12831 };
12832 static const struct message WmShowNoActivate_1[] = {
12833 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12834 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12835 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12836 { WM_MOVE, sent|defwinproc|optional },
12837 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12838 { 0 }
12839 };
12840 static const struct message WmShowNoActivate_2[] = {
12841 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12842 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12843 { HCBT_ACTIVATE, hook|optional },
12844 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12845 { HCBT_SETFOCUS, hook|optional },
12846 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12847 { WM_MOVE, sent|defwinproc },
12848 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12849 { HCBT_SETFOCUS, hook|optional },
12850 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12851 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12852 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12853 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12854 { 0 }
12855 };
12856 static const struct message WmShowNA_1[] = {
12857 { WM_SHOWWINDOW, sent|wparam, 1 },
12858 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12859 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12860 { 0 }
12861 };
12862 static const struct message WmShowNA_2[] = {
12863 { WM_SHOWWINDOW, sent|wparam, 1 },
12864 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12865 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12866 { 0 }
12867 };
12868 static const struct message WmRestore_1[] = {
12869 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12870 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12871 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12872 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12873 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12874 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12875 { WM_MOVE, sent|defwinproc },
12876 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12877 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12878 { 0 }
12879 };
12880 static const struct message WmRestore_2[] = {
12881 { WM_SHOWWINDOW, sent|wparam, 1 },
12882 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12883 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12884 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12885 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12886 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12887 { 0 }
12888 };
12889 static const struct message WmRestore_3[] = {
12890 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12891 { WM_GETMINMAXINFO, sent },
12892 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12893 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12894 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12895 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12896 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12897 { WM_MOVE, sent|defwinproc },
12898 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12899 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12900 { 0 }
12901 };
12902 static const struct message WmRestore_4[] = {
12903 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
12904 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12905 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12906 { WM_MOVE, sent|defwinproc|optional },
12907 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12908 { 0 }
12909 };
12910 static const struct message WmRestore_5[] = {
12911 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
12912 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12913 { HCBT_ACTIVATE, hook|optional },
12914 { HCBT_SETFOCUS, hook|optional },
12915 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12916 { WM_MOVE, sent|defwinproc|optional },
12917 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12918 { 0 }
12919 };
12920 static const struct message WmHide_1[] = {
12921 { WM_SHOWWINDOW, sent|wparam, 0 },
12922 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
12923 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
12924 { HCBT_ACTIVATE, hook|optional },
12925 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12926 { 0 }
12927 };
12928 static const struct message WmHide_2[] = {
12929 { WM_SHOWWINDOW, sent|wparam, 0 },
12930 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12931 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12932 { HCBT_ACTIVATE, hook|optional },
12933 { 0 }
12934 };
12935 static const struct message WmHide_3[] = {
12936 { WM_SHOWWINDOW, sent|wparam, 0 },
12937 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12938 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12939 { HCBT_SETFOCUS, hook|optional },
12940 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12941 { 0 }
12942 };
12943 static const struct message WmShowMinimized_1[] = {
12944 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12945 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12946 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12947 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12948 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12949 { WM_MOVE, sent|defwinproc },
12950 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12951 { 0 }
12952 };
12953 static const struct message WmMinimize_1[] = {
12954 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12955 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12956 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12957 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12958 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12959 { WM_MOVE, sent|defwinproc },
12960 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12961 { 0 }
12962 };
12963 static const struct message WmMinimize_2[] = {
12964 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12965 { HCBT_SETFOCUS, hook|optional },
12966 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12967 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12968 { WM_MOVE, sent|defwinproc },
12969 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12970 { 0 }
12971 };
12972 static const struct message WmMinimize_3[] = {
12973 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12974 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12975 { HCBT_ACTIVATE, hook|optional },
12976 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12977 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12978 { WM_MOVE, sent|defwinproc },
12979 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12980 { 0 }
12981 };
12982 static const struct message WmShowMinNoActivate[] = {
12983 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12984 { WM_WINDOWPOSCHANGING, sent },
12985 { WM_WINDOWPOSCHANGED, sent },
12986 { WM_MOVE, sent|defwinproc|optional },
12987 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12988 { 0 }
12989 };
12990 static const struct message WmMinMax_1[] = {
12991 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12992 { 0 }
12993 };
12994 static const struct message WmMinMax_2[] = {
12995 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12996 { WM_GETMINMAXINFO, sent|optional },
12997 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
12998 { HCBT_ACTIVATE, hook|optional },
12999 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13000 { HCBT_SETFOCUS, hook|optional },
13001 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13002 { WM_MOVE, sent|defwinproc|optional },
13003 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
13004 { HCBT_SETFOCUS, hook|optional },
13005 { 0 }
13006 };
13007 static const struct message WmMinMax_3[] = {
13008 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13009 { HCBT_SETFOCUS, hook|optional },
13010 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13011 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13012 { WM_MOVE, sent|defwinproc|optional },
13013 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13014 { 0 }
13015 };
13016 static const struct message WmMinMax_4[] = {
13017 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13018 { 0 }
13019 };
13020 static const struct message WmShowMaximized_1[] = {
13021 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13022 { WM_GETMINMAXINFO, sent },
13023 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13024 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13025 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13026 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13027 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13028 { WM_MOVE, sent|defwinproc },
13029 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13030 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13031 { 0 }
13032 };
13033 static const struct message WmShowMaximized_2[] = {
13034 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13035 { WM_GETMINMAXINFO, sent },
13036 { WM_WINDOWPOSCHANGING, sent|optional },
13037 { HCBT_ACTIVATE, hook|optional },
13038 { WM_WINDOWPOSCHANGED, sent|optional },
13039 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
13040 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
13041 { WM_WINDOWPOSCHANGING, sent|optional },
13042 { HCBT_SETFOCUS, hook|optional },
13043 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13044 { WM_MOVE, sent|defwinproc },
13045 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13046 { HCBT_SETFOCUS, hook|optional },
13047 { 0 }
13048 };
13049 static const struct message WmShowMaximized_3[] = {
13050 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13051 { WM_GETMINMAXINFO, sent|optional },
13052 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13053 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13054 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13055 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13056 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13057 { WM_MOVE, sent|defwinproc|optional },
13058 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13059 { 0 }
13060 };
13061
13062 static void test_ShowWindow(void)
13063 {
13064 /* ShowWindow commands in random order */
13065 static const struct
13066 {
13067 INT cmd; /* ShowWindow command */
13068 LPARAM ret; /* ShowWindow return value */
13069 DWORD style; /* window style after the command */
13070 const struct message *msg; /* message sequence the command produces */
13071 INT wp_cmd, wp_flags; /* window placement after the command */
13072 POINT wp_min, wp_max; /* window placement after the command */
13073 BOOL todo_msg; /* message sequence doesn't match what Wine does */
13074 } sw[] =
13075 {
13076 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
13077 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13078 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
13079 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13080 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
13081 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13082 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13083 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13084 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
13085 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13086 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
13087 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13088 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
13089 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13090 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13091 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13092 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
13093 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13094 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13095 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13096 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
13097 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13098 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
13099 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13100 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
13101 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13102 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13103 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13104 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
13105 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13106 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13107 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13108 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
13109 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13110 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13111 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13112 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13113 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13114 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13115 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13116 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13117 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13118 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13119 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13120 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13121 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13122 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13123 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13124 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13125 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13126 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13127 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13128 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13129 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13130 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13131 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13132 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13133 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13134 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13135 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13136 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13137 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13138 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13139 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13140 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13141 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13142 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13143 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13144 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13145 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13146 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13147 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13148 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13149 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13150 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13151 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13152 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13153 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13154 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13155 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13156 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13157 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13158 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13159 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13160 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13161 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13162 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13163 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13164 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13165 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13166 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13167 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13168 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13169 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13170 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13171 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13172 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13173 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13174 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13175 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13176 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13177 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13178 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13179 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13180 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13181 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13182 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13183 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13184 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13185 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13186 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13187 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13188 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13189 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13190 };
13191 HWND hwnd;
13192 DWORD style;
13193 LPARAM ret;
13194 INT i;
13195 WINDOWPLACEMENT wp;
13196 RECT win_rc, work_rc = {0, 0, 0, 0};
13197
13198 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13199 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13200 120, 120, 90, 90,
13201 0, 0, 0, NULL);
13202 assert(hwnd);
13203
13204 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13205 ok(style == 0, "expected style 0, got %08x\n", style);
13206
13207 flush_events();
13208 flush_sequence();
13209
13210 if (pGetMonitorInfoA && pMonitorFromPoint)
13211 {
13212 HMONITOR hmon;
13213 MONITORINFO mi;
13214 POINT pt = {0, 0};
13215
13216 SetLastError(0xdeadbeef);
13217 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13218 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13219
13220 mi.cbSize = sizeof(mi);
13221 SetLastError(0xdeadbeef);
13222 ret = pGetMonitorInfoA(hmon, &mi);
13223 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13224 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13225 wine_dbgstr_rect(&mi.rcWork));
13226 work_rc = mi.rcWork;
13227 }
13228
13229 GetWindowRect(hwnd, &win_rc);
13230 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13231
13232 wp.length = sizeof(wp);
13233 SetLastError(0xdeadbeaf);
13234 ret = GetWindowPlacement(hwnd, &wp);
13235 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13236 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13237 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13238 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13239 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13240 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13241 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13242 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13243 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13244 wine_dbgstr_rect(&wp.rcNormalPosition));
13245
13246 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
13247 {
13248 static const char * const sw_cmd_name[13] =
13249 {
13250 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13251 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13252 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13253 "SW_NORMALNA" /* 0xCC */
13254 };
13255 char comment[64];
13256 INT idx; /* index into the above array of names */
13257
13258 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13259
13260 style = GetWindowLongA(hwnd, GWL_STYLE);
13261 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13262 ret = ShowWindow(hwnd, sw[i].cmd);
13263 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13264 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13265 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13266
13267 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13268 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13269
13270 wp.length = sizeof(wp);
13271 SetLastError(0xdeadbeaf);
13272 ret = GetWindowPlacement(hwnd, &wp);
13273 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13274 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13275 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13276
13277 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13278 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13279 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13280 {
13281 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13282 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13283 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13284 }
13285 else
13286 {
13287 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13288 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13289 }
13290
13291 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13292 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13293 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13294
13295 if (0) /* FIXME: Wine behaves completely different here */
13296 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13297 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13298 }
13299 DestroyWindow(hwnd);
13300 flush_events();
13301 }
13302
13303 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13304 {
13305 struct recvd_message msg;
13306
13307 if (ignore_message( message )) return 0;
13308
13309 msg.hwnd = hwnd;
13310 msg.message = message;
13311 msg.flags = sent|wparam|lparam;
13312 msg.wParam = wParam;
13313 msg.lParam = lParam;
13314 msg.descr = "dialog";
13315 add_message(&msg);
13316
13317 /* calling DefDlgProc leads to a recursion under XP */
13318
13319 switch (message)
13320 {
13321 case WM_INITDIALOG:
13322 return lParam;
13323
13324 case WM_GETDLGCODE:
13325 return 0;
13326 }
13327 return 1;
13328 }
13329
13330 static WNDPROC orig_edit_proc;
13331 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13332 {
13333 struct recvd_message msg;
13334
13335 if (ignore_message( message )) return 0;
13336
13337 msg.hwnd = hwnd;
13338 msg.message = message;
13339 msg.flags = sent|wparam|lparam;
13340 msg.wParam = wp;
13341 msg.lParam = lp;
13342 msg.descr = "edit";
13343 add_message(&msg);
13344
13345 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13346 }
13347
13348 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13349 {
13350 struct recvd_message msg;
13351
13352 if (ignore_message( message )) return 0;
13353
13354 msg.hwnd = hwnd;
13355 msg.message = message;
13356 msg.flags = sent|wparam|lparam|parent;
13357 msg.wParam = wParam;
13358 msg.lParam = lParam;
13359 msg.descr = "dialog";
13360 add_message(&msg);
13361
13362 if (message == WM_INITDIALOG)
13363 {
13364 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13365 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13366 }
13367
13368 return 1;
13369 }
13370
13371 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13372 {
13373 ok( 0, "should not be called since DefDlgProc is not used\n" );
13374 return 0;
13375 }
13376
13377 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13378 {
13379 struct recvd_message msg;
13380
13381 if (!ignore_message( message ))
13382 {
13383 msg.hwnd = hwnd;
13384 msg.message = message;
13385 msg.flags = sent|wparam|lparam|parent;
13386 msg.wParam = wParam;
13387 msg.lParam = lParam;
13388 msg.descr = "dialog";
13389 add_message(&msg);
13390 }
13391 if (message == WM_INITDIALOG)
13392 {
13393 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13394 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13395 return 1;
13396 }
13397 return DefWindowProcW( hwnd, message, wParam, lParam );
13398 }
13399
13400 static const struct message WmDefDlgSetFocus_1[] = {
13401 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13402 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13403 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13404 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13405 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13406 { HCBT_SETFOCUS, hook },
13407 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13408 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13409 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13410 { WM_SETFOCUS, sent|wparam, 0 },
13411 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13412 { WM_CTLCOLOREDIT, sent },
13413 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13414 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13415 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13416 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13417 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13418 { 0 }
13419 };
13420 static const struct message WmDefDlgSetFocus_2[] = {
13421 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13422 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13423 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13424 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13425 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13426 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13427 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13428 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13429 { 0 }
13430 };
13431 /* Creation of a dialog */
13432 static const struct message WmCreateDialogParamSeq_0[] = {
13433 { HCBT_CREATEWND, hook },
13434 { WM_NCCREATE, sent },
13435 { WM_NCCALCSIZE, sent|wparam, 0 },
13436 { WM_CREATE, sent },
13437 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13438 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13439 { WM_MOVE, sent },
13440 { WM_SETFONT, sent },
13441 { WM_INITDIALOG, sent },
13442 { WM_CHANGEUISTATE, sent|optional },
13443 { 0 }
13444 };
13445 /* Creation of a dialog */
13446 static const struct message WmCreateDialogParamSeq_1[] = {
13447 { HCBT_CREATEWND, hook },
13448 { WM_NCCREATE, sent },
13449 { WM_NCCALCSIZE, sent|wparam, 0 },
13450 { WM_CREATE, sent },
13451 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13452 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13453 { WM_MOVE, sent },
13454 { WM_SETFONT, sent },
13455 { WM_INITDIALOG, sent },
13456 { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13457 { HCBT_SETFOCUS, hook },
13458 { HCBT_ACTIVATE, hook },
13459 { WM_QUERYNEWPALETTE, sent|optional },
13460 { WM_PALETTEISCHANGING, sent|optional },
13461 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13462 { WM_ACTIVATEAPP, sent|wparam, 1 },
13463 { WM_NCACTIVATE, sent },
13464 { WM_ACTIVATE, sent|wparam, 1 },
13465 { WM_SETFOCUS, sent },
13466 { WM_CHANGEUISTATE, sent|optional },
13467 { 0 }
13468 };
13469 /* Creation of a dialog */
13470 static const struct message WmCreateDialogParamSeq_2[] = {
13471 { HCBT_CREATEWND, hook },
13472 { WM_NCCREATE, sent },
13473 { WM_NCCALCSIZE, sent|wparam, 0 },
13474 { WM_CREATE, sent },
13475 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13476 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13477 { WM_MOVE, sent },
13478 { WM_CHANGEUISTATE, sent|optional },
13479 { 0 }
13480 };
13481
13482 static const struct message WmCreateDialogParamSeq_3[] = {
13483 { HCBT_CREATEWND, hook },
13484 { WM_SETFONT, sent|parent },
13485 { WM_INITDIALOG, sent|parent },
13486 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13487 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13488 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13489 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13490 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13491 { HCBT_ACTIVATE, hook },
13492 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13493 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13494 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13495 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13496 { WM_NCACTIVATE, sent|parent },
13497 { WM_ACTIVATE, sent|parent|wparam, 1 },
13498 { WM_SETFOCUS, sent },
13499 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13500 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13501 { WM_USER, sent|parent },
13502 { WM_CHANGEUISTATE, sent|parent|optional },
13503 { 0 }
13504 };
13505
13506 static const struct message WmCreateDialogParamSeq_4[] = {
13507 { HCBT_CREATEWND, hook },
13508 { WM_NCCREATE, sent|parent },
13509 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13510 { WM_CREATE, sent|parent },
13511 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13512 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13513 { WM_MOVE, sent|parent },
13514 { WM_SETFONT, sent|parent },
13515 { WM_INITDIALOG, sent|parent },
13516 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13517 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13518 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13519 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13520 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13521 { HCBT_ACTIVATE, hook },
13522 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13523 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13524 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13525 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13526 { WM_NCACTIVATE, sent|parent },
13527 { WM_ACTIVATE, sent|parent|wparam, 1 },
13528 { HCBT_SETFOCUS, hook },
13529 { WM_SETFOCUS, sent|parent },
13530 { WM_KILLFOCUS, sent|parent },
13531 { WM_SETFOCUS, sent },
13532 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13533 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13534 { WM_USER, sent|parent },
13535 { WM_CHANGEUISTATE, sent|parent|optional },
13536 { WM_UPDATEUISTATE, sent|parent|optional },
13537 { WM_UPDATEUISTATE, sent|optional },
13538 { 0 }
13539 };
13540
13541 static void test_dialog_messages(void)
13542 {
13543 WNDCLASSA cls;
13544 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
13545 LRESULT ret;
13546
13547 #define set_selection(hctl, start, end) \
13548 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
13549 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
13550
13551 #define check_selection(hctl, start, end) \
13552 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
13553 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
13554
13555 subclass_edit();
13556
13557 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
13558 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13559 0, 0, 100, 100, 0, 0, 0, NULL);
13560 ok(hdlg != 0, "Failed to create custom dialog window\n");
13561
13562 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
13563 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13564 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
13565 ok(hedit1 != 0, "Failed to create edit control\n");
13566 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
13567 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13568 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
13569 ok(hedit2 != 0, "Failed to create edit control\n");
13570
13571 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
13572 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
13573
13574 hfocus = GetFocus();
13575 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13576
13577 SetFocus(hedit2);
13578 hfocus = GetFocus();
13579 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
13580
13581 check_selection(hedit1, 0, 0);
13582 check_selection(hedit2, 0, 0);
13583
13584 set_selection(hedit2, 0, -1);
13585 check_selection(hedit2, 0, 3);
13586
13587 SetFocus(0);
13588 hfocus = GetFocus();
13589 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13590
13591 flush_sequence();
13592 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13593 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13594 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
13595
13596 hfocus = GetFocus();
13597 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13598
13599 check_selection(hedit1, 0, 5);
13600 check_selection(hedit2, 0, 3);
13601
13602 flush_sequence();
13603 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13604 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13605 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
13606
13607 hfocus = GetFocus();
13608 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13609
13610 check_selection(hedit1, 0, 5);
13611 check_selection(hedit2, 0, 3);
13612
13613 EndDialog(hdlg, 0);
13614 DestroyWindow(hedit1);
13615 DestroyWindow(hedit2);
13616 DestroyWindow(hdlg);
13617 flush_sequence();
13618
13619 #undef set_selection
13620 #undef check_selection
13621
13622 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13623 cls.lpszClassName = "MyDialogClass";
13624 cls.hInstance = GetModuleHandleA(NULL);
13625 /* need a cast since a dlgproc is used as a wndproc */
13626 cls.lpfnWndProc = test_dlg_proc;
13627 if (!RegisterClassA(&cls)) assert(0);
13628
13629 SetFocus(0);
13630 flush_sequence();
13631 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13632 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13633 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
13634 hfocus = GetFocus();
13635 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13636 EndDialog(hdlg, 0);
13637 DestroyWindow(hdlg);
13638 flush_sequence();
13639
13640 SetFocus(0);
13641 flush_sequence();
13642 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
13643 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13644 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13645 hfocus = GetFocus();
13646 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13647 EndDialog(hdlg, 0);
13648 DestroyWindow(hdlg);
13649 flush_sequence();
13650
13651 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13652 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13653 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13654 EndDialog(hdlg, 0);
13655 DestroyWindow(hdlg);
13656 flush_sequence();
13657
13658 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13659 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13660 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13661 EndDialog(hdlg, 0);
13662 DestroyWindow(hdlg);
13663 flush_sequence();
13664
13665 UnregisterClassA( cls.lpszClassName, cls.hInstance );
13666 cls.lpfnWndProc = test_dlg_proc4;
13667 ok( RegisterClassA(&cls), "failed to register class again\n" );
13668 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13669 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13670 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13671 EndDialog(hdlg, 0);
13672 DestroyWindow(hdlg);
13673 flush_sequence();
13674
13675 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13676
13677 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13678 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13679 100, 100, 200, 200, 0, 0, 0, NULL);
13680 ok (parent != 0, "Failed to create parent window\n");
13681
13682 /* This child has no parent set. We will later call SetParent on it,
13683 * so that it will have a parent set, but no WS_CHILD style. */
13684 child = CreateWindowExA(0, "TestWindowClass", "Test child",
13685 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13686 100, 100, 200, 200, 0, 0, 0, NULL);
13687 ok (child != 0, "Failed to create child window\n");
13688
13689 /* This is a regular child window. When used as an owner, the other
13690 * child window will be used. */
13691 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13692 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13693 100, 100, 200, 200, child, 0, 0, NULL);
13694 ok (child2 != 0, "Failed to create child window\n");
13695
13696 SetParent(child, parent);
13697 SetFocus(child);
13698
13699 flush_sequence();
13700 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13701 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13702
13703 DestroyWindow(child2);
13704 DestroyWindow(child);
13705 DestroyWindow(parent);
13706 flush_sequence();
13707 }
13708
13709 static void test_enddialog_seq(HWND dialog, HWND owner)
13710 {
13711 const struct message seq[] = {
13712 { WM_ENABLE, sent },
13713 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13714 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13715 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13716 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13717 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13718 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13719 { WM_QUERYNEWPALETTE, sent|optional },
13720 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13721 { WM_GETTEXT, sent|optional|defwinproc },
13722 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13723 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13724 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13725 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13726 { 0 }
13727 };
13728
13729 flush_sequence();
13730 EndDialog(dialog, 0);
13731 ok_sequence(seq, "EndDialog", FALSE);
13732 }
13733
13734 static void test_enddialog_seq2(HWND dialog, HWND owner)
13735 {
13736 const struct message seq[] = {
13737 { WM_ENABLE, parent|sent },
13738 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13739 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13740 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13741 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13742 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13743 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13744 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13745 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13746 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13747 { 0 }
13748 };
13749
13750 flush_sequence();
13751 EndDialog(dialog, 0);
13752 ok_sequence(seq, "EndDialog2", FALSE);
13753 }
13754
13755 static void test_EndDialog(void)
13756 {
13757 HWND hparent, hother, hactive, hdlg, hchild;
13758 WNDCLASSA cls;
13759
13760 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13761 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13762 100, 100, 200, 200, 0, 0, 0, NULL);
13763 ok (hparent != 0, "Failed to create parent window\n");
13764
13765 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
13766 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13767 200, 100, 200, 200, 0, 0, 0, NULL);
13768 ok (hother != 0, "Failed to create parent window\n");
13769
13770 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13771 cls.lpszClassName = "MyDialogClass";
13772 cls.hInstance = GetModuleHandleA(NULL);
13773 cls.lpfnWndProc = test_dlg_proc;
13774 if (!RegisterClassA(&cls)) assert(0);
13775
13776 flush_sequence();
13777 SetForegroundWindow(hother);
13778 hactive = GetForegroundWindow();
13779 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
13780
13781 /* create a dialog where the parent is disabled, this parent should be
13782 * enabled and receive focus when dialog exits */
13783 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
13784 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13785 SetForegroundWindow(hdlg);
13786 hactive = GetForegroundWindow();
13787 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
13788 EndDialog(hdlg, 0);
13789 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13790 hactive = GetForegroundWindow();
13791 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13792 DestroyWindow(hdlg);
13793 flush_sequence();
13794
13795 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
13796 EnableWindow(hparent, FALSE);
13797 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
13798 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13799 0, 0, 100, 100, hparent, 0, 0, NULL);
13800 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13801 flush_sequence();
13802 SetForegroundWindow(hother);
13803 flush_sequence();
13804 hactive = GetForegroundWindow();
13805 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
13806 hactive = GetActiveWindow();
13807 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
13808 EndDialog(hdlg, 0);
13809 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13810 hactive = GetForegroundWindow();
13811 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13812 DestroyWindow(hdlg);
13813 flush_sequence();
13814
13815 DestroyWindow( hparent );
13816
13817 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13818 WS_POPUP | WS_VISIBLE | WS_DISABLED,
13819 100, 100, 200, 200, 0, 0, 0, NULL);
13820 ok (hparent != 0, "Failed to create parent window\n");
13821
13822 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
13823 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13824 0, 0, 0, 0, 0, 0, 0, NULL);
13825 ok (hchild != 0, "Failed to create child window\n");
13826
13827 SetParent(hchild, hparent);
13828
13829 flush_sequence();
13830 SetForegroundWindow(hother);
13831 hactive = GetForegroundWindow();
13832 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13833
13834 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13835 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13836
13837 SetForegroundWindow(hdlg);
13838 test_enddialog_seq(hdlg, hchild);
13839
13840 hactive = GetForegroundWindow();
13841 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13842
13843 DestroyWindow(hdlg);
13844
13845 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
13846 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
13847
13848 SetForegroundWindow(hother);
13849 hactive = GetForegroundWindow();
13850 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13851
13852 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13853 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13854
13855 SetForegroundWindow(hdlg);
13856 test_enddialog_seq2(hdlg, hparent);
13857
13858 hactive = GetForegroundWindow();
13859 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13860 DestroyWindow(hdlg);
13861 DestroyWindow(hchild);
13862 DestroyWindow(hparent);
13863 DestroyWindow(hother);
13864 flush_sequence();
13865
13866 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13867 }
13868
13869 static void test_nullCallback(void)
13870 {
13871 HWND hwnd;
13872
13873 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13874 100, 100, 200, 200, 0, 0, 0, NULL);
13875 ok (hwnd != 0, "Failed to create overlapped window\n");
13876
13877 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
13878 flush_events();
13879 DestroyWindow(hwnd);
13880 }
13881
13882 /* SetActiveWindow( 0 ) hwnd visible */
13883 static const struct message SetActiveWindowSeq0[] =
13884 {
13885 { HCBT_ACTIVATE, hook|optional },
13886 { WM_NCACTIVATE, sent|wparam, 0 },
13887 { WM_GETTEXT, sent|defwinproc|optional },
13888 { WM_ACTIVATE, sent|wparam, 0 },
13889 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13890 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13891 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13892 { WM_KILLFOCUS, sent|optional },
13893 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13894 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13895 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13896 { WM_GETTEXT, sent|defwinproc|optional },
13897 { WM_ACTIVATE, sent|wparam|optional, 1 },
13898 { HCBT_SETFOCUS, hook|optional },
13899 { WM_KILLFOCUS, sent|defwinproc|optional },
13900 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13901 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13902 { WM_IME_SETCONTEXT, sent|optional },
13903 { WM_IME_SETCONTEXT, sent|optional },
13904 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13905 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13906 { WM_SETFOCUS, sent|defwinproc|optional },
13907 { WM_GETTEXT, sent|optional },
13908 { 0 }
13909 };
13910 /* SetActiveWindow( hwnd ) hwnd visible */
13911 static const struct message SetActiveWindowSeq1[] =
13912 {
13913 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13914 { 0 }
13915 };
13916 /* SetActiveWindow( popup ) hwnd visible, popup visible */
13917 static const struct message SetActiveWindowSeq2[] =
13918 {
13919 { HCBT_ACTIVATE, hook },
13920 { WM_NCACTIVATE, sent|wparam, 0 },
13921 { WM_GETTEXT, sent|defwinproc|optional },
13922 { WM_ACTIVATE, sent|wparam, 0 },
13923 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13924 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13925 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13926 { WM_NCPAINT, sent|optional },
13927 { WM_GETTEXT, sent|defwinproc|optional },
13928 { WM_ERASEBKGND, sent|optional },
13929 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13930 { WM_NCACTIVATE, sent|wparam, 1 },
13931 { WM_GETTEXT, sent|defwinproc|optional },
13932 { WM_ACTIVATE, sent|wparam, 1 },
13933 { HCBT_SETFOCUS, hook },
13934 { WM_KILLFOCUS, sent|defwinproc },
13935 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13936 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13937 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13938 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13939 { WM_SETFOCUS, sent|defwinproc },
13940 { WM_GETTEXT, sent|optional },
13941 { 0 }
13942 };
13943
13944 /* SetActiveWindow( hwnd ) hwnd not visible */
13945 static const struct message SetActiveWindowSeq3[] =
13946 {
13947 { HCBT_ACTIVATE, hook },
13948 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13949 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13950 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13951 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13952 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13953 { WM_ACTIVATEAPP, sent|wparam, 1 },
13954 { WM_ACTIVATEAPP, sent|wparam, 1 },
13955 { WM_NCACTIVATE, sent|wparam, 1 },
13956 { WM_ACTIVATE, sent|wparam, 1 },
13957 { HCBT_SETFOCUS, hook },
13958 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13959 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13960 { WM_SETFOCUS, sent|defwinproc },
13961 { 0 }
13962 };
13963 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
13964 static const struct message SetActiveWindowSeq4[] =
13965 {
13966 { HCBT_ACTIVATE, hook },
13967 { WM_NCACTIVATE, sent|wparam, 0 },
13968 { WM_GETTEXT, sent|defwinproc|optional },
13969 { WM_ACTIVATE, sent|wparam, 0 },
13970 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13971 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13972 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13973 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13974 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13975 { WM_NCACTIVATE, sent|wparam, 1 },
13976 { WM_GETTEXT, sent|defwinproc|optional },
13977 { WM_ACTIVATE, sent|wparam, 1 },
13978 { HCBT_SETFOCUS, hook },
13979 { WM_KILLFOCUS, sent|defwinproc },
13980 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13981 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13982 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13983 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13984 { WM_SETFOCUS, sent|defwinproc },
13985 { 0 }
13986 };
13987
13988
13989 static void test_SetActiveWindow(void)
13990 {
13991 HWND hwnd, popup, ret;
13992
13993 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13994 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13995 100, 100, 200, 200, 0, 0, 0, NULL);
13996
13997 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13998 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
13999 100, 100, 200, 200, hwnd, 0, 0, NULL);
14000
14001 ok(hwnd != 0, "Failed to create overlapped window\n");
14002 ok(popup != 0, "Failed to create popup window\n");
14003 SetForegroundWindow( popup );
14004 flush_sequence();
14005
14006 trace("SetActiveWindow(0)\n");
14007 ret = SetActiveWindow(0);
14008 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
14009 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
14010 flush_sequence();
14011
14012 trace("SetActiveWindow(hwnd), hwnd visible\n");
14013 ret = SetActiveWindow(hwnd);
14014 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
14015 flush_sequence();
14016
14017 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
14018 ret = SetActiveWindow(popup);
14019 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
14020 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
14021 flush_sequence();
14022
14023 ShowWindow(hwnd, SW_HIDE);
14024 ShowWindow(popup, SW_HIDE);
14025 flush_sequence();
14026
14027 trace("SetActiveWindow(hwnd), hwnd not visible\n");
14028 ret = SetActiveWindow(hwnd);
14029 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
14030 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
14031 flush_sequence();
14032
14033 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
14034 ret = SetActiveWindow(popup);
14035 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
14036 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
14037 flush_sequence();
14038
14039 trace("done\n");
14040
14041 DestroyWindow(hwnd);
14042 }
14043
14044 static const struct message SetForegroundWindowSeq[] =
14045 {
14046 { WM_NCACTIVATE, sent|wparam, 0 },
14047 { WM_GETTEXT, sent|defwinproc|optional },
14048 { WM_ACTIVATE, sent|wparam, 0 },
14049 { WM_ACTIVATEAPP, sent|wparam, 0 },
14050 { WM_KILLFOCUS, sent },
14051 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
14052 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
14053 { 0 }
14054 };
14055
14056 static void test_SetForegroundWindow(void)
14057 {
14058 HWND hwnd;
14059
14060 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
14061 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14062 100, 100, 200, 200, 0, 0, 0, NULL);
14063 ok (hwnd != 0, "Failed to create overlapped window\n");
14064 SetForegroundWindow( hwnd );
14065 flush_sequence();
14066
14067 trace("SetForegroundWindow( 0 )\n");
14068 SetForegroundWindow( 0 );
14069 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
14070 trace("SetForegroundWindow( GetDesktopWindow() )\n");
14071 SetForegroundWindow( GetDesktopWindow() );
14072 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
14073 "foreground top level window", FALSE);
14074 trace("done\n");
14075
14076 DestroyWindow(hwnd);
14077 }
14078
14079 static DWORD get_input_codepage( void )
14080 {
14081 DWORD cp;
14082 int ret;
14083 HKL hkl = GetKeyboardLayout( 0 );
14084
14085 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
14086 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
14087 if (!ret) cp = CP_ACP;
14088 return cp;
14089 }
14090
14091 static void test_dbcs_wm_char(void)
14092 {
14093 BYTE dbch[2];
14094 WCHAR wch, bad_wch;
14095 HWND hwnd, hwnd2;
14096 MSG msg;
14097 DWORD time;
14098 POINT pt;
14099 DWORD_PTR res;
14100 CPINFOEXA cpinfo;
14101 UINT i, j, k;
14102 struct message wmCharSeq[2];
14103 BOOL ret;
14104 DWORD cp = get_input_codepage();
14105
14106 if (!pGetCPInfoExA)
14107 {
14108 win_skip("GetCPInfoExA is not available\n");
14109 return;
14110 }
14111
14112 pGetCPInfoExA( cp, 0, &cpinfo );
14113 if (cpinfo.MaxCharSize != 2)
14114 {
14115 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14116 return;
14117 }
14118
14119 dbch[0] = dbch[1] = 0;
14120 wch = 0;
14121 bad_wch = cpinfo.UnicodeDefaultChar;
14122 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14123 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14124 for (k = 128; k <= 255; k++)
14125 {
14126 char str[2];
14127 WCHAR wstr[2];
14128 str[0] = j;
14129 str[1] = k;
14130 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14131 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14132 (BYTE)str[0] == j && (BYTE)str[1] == k &&
14133 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14134 {
14135 dbch[0] = j;
14136 dbch[1] = k;
14137 wch = wstr[0];
14138 break;
14139 }
14140 }
14141
14142 if (!wch)
14143 {
14144 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14145 return;
14146 }
14147 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14148 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14149
14150 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14151 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14152 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14153 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14154 ok (hwnd != 0, "Failed to create overlapped window\n");
14155 ok (hwnd2 != 0, "Failed to create overlapped window\n");
14156 flush_sequence();
14157
14158 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14159 wmCharSeq[0].message = WM_CHAR;
14160 wmCharSeq[0].flags = sent|wparam;
14161 wmCharSeq[0].wParam = wch;
14162
14163 /* posted message */
14164 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14165 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14166 ok( !ret, "got message %x\n", msg.message );
14167 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14168 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14169 ok( ret, "no message\n" );
14170 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14171 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14172 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14173 ok( !ret, "got message %x\n", msg.message );
14174
14175 /* posted thread message */
14176 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14177 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14178 ok( !ret, "got message %x\n", msg.message );
14179 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14180 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14181 ok( ret, "no message\n" );
14182 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14183 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14184 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14185 ok( !ret, "got message %x\n", msg.message );
14186
14187 /* sent message */
14188 flush_sequence();
14189 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14190 ok_sequence( WmEmptySeq, "no messages", FALSE );
14191 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14192 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14193 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14194 ok( !ret, "got message %x\n", msg.message );
14195
14196 /* sent message with timeout */
14197 flush_sequence();
14198 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14199 ok_sequence( WmEmptySeq, "no messages", FALSE );
14200 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14201 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14202 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14203 ok( !ret, "got message %x\n", msg.message );
14204
14205 /* sent message with timeout and callback */
14206 flush_sequence();
14207 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14208 ok_sequence( WmEmptySeq, "no messages", FALSE );
14209 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14210 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14211 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14212 ok( !ret, "got message %x\n", msg.message );
14213
14214 /* sent message with callback */
14215 flush_sequence();
14216 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14217 ok_sequence( WmEmptySeq, "no messages", FALSE );
14218 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14219 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14220 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14221 ok( !ret, "got message %x\n", msg.message );
14222
14223 /* direct window proc call */
14224 flush_sequence();
14225 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14226 ok_sequence( WmEmptySeq, "no messages", FALSE );
14227 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14228 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14229
14230 /* dispatch message */
14231 msg.hwnd = hwnd;
14232 msg.message = WM_CHAR;
14233 msg.wParam = dbch[0];
14234 msg.lParam = 0;
14235 DispatchMessageA( &msg );
14236 ok_sequence( WmEmptySeq, "no messages", FALSE );
14237 msg.wParam = dbch[1];
14238 DispatchMessageA( &msg );
14239 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14240
14241 /* window handle is irrelevant */
14242 flush_sequence();
14243 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14244 ok_sequence( WmEmptySeq, "no messages", FALSE );
14245 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14246 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14247 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14248 ok( !ret, "got message %x\n", msg.message );
14249
14250 /* interleaved post and send */
14251 flush_sequence();
14252 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14253 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14254 ok_sequence( WmEmptySeq, "no messages", FALSE );
14255 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14256 ok( !ret, "got message %x\n", msg.message );
14257 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14258 ok_sequence( WmEmptySeq, "no messages", FALSE );
14259 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14260 ok( ret, "no message\n" );
14261 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14262 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14263 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14264 ok( !ret, "got message %x\n", msg.message );
14265 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14266 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14267 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14268 ok( !ret, "got message %x\n", msg.message );
14269
14270 /* interleaved sent message and winproc */
14271 flush_sequence();
14272 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14273 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14274 ok_sequence( WmEmptySeq, "no messages", FALSE );
14275 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14276 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14277 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14278 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14279
14280 /* interleaved winproc and dispatch */
14281 msg.hwnd = hwnd;
14282 msg.message = WM_CHAR;
14283 msg.wParam = dbch[0];
14284 msg.lParam = 0;
14285 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14286 DispatchMessageA( &msg );
14287 ok_sequence( WmEmptySeq, "no messages", FALSE );
14288 msg.wParam = dbch[1];
14289 DispatchMessageA( &msg );
14290 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14291 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14292 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14293
14294 /* interleaved sends */
14295 flush_sequence();
14296 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14297 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14298 ok_sequence( WmEmptySeq, "no messages", FALSE );
14299 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14300 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14301 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14302 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14303
14304 /* dbcs WM_CHAR */
14305 flush_sequence();
14306 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14307 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14308 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14309 ok( !ret, "got message %x\n", msg.message );
14310
14311 /* other char messages are not magic */
14312 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14313 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14314 ok( ret, "no message\n" );
14315 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14316 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14317 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14318 ok( !ret, "got message %x\n", msg.message );
14319 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14320 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14321 ok( ret, "no message\n" );
14322 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14323 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14324 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14325 ok( !ret, "got message %x\n", msg.message );
14326
14327 /* test retrieving messages */
14328
14329 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14330 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14331 ok( ret, "no message\n" );
14332 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14333 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14334 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14335 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14336 ok( ret, "no message\n" );
14337 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14338 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14339 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14340 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14341 ok( !ret, "got message %x\n", msg.message );
14342
14343 /* message filters */
14344 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14345 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14346 ok( ret, "no message\n" );
14347 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14348 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14349 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14350 /* message id is filtered, hwnd is not */
14351 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14352 ok( !ret, "no message\n" );
14353 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14354 ok( ret, "no message\n" );
14355 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14356 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14357 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14358 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14359 ok( !ret, "got message %x\n", msg.message );
14360
14361 /* mixing GetMessage and PostMessage */
14362 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14363 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14364 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14365 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14366 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14367 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14368 time = msg.time;
14369 pt = msg.pt;
14370 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14371 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14372 ok( ret, "no message\n" );
14373 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14374 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14375 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14376 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14377 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14378 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 );
14379 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14380 ok( !ret, "got message %x\n", msg.message );
14381
14382 /* without PM_REMOVE */
14383 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14384 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14385 ok( ret, "no message\n" );
14386 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14387 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14388 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14389 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14390 ok( ret, "no message\n" );
14391 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14392 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14393 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14394 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14395 ok( ret, "no message\n" );
14396 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14397 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14398 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14399 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14400 ok( ret, "no message\n" );
14401 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14402 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14403 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14404 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14405 ok( !ret, "got message %x\n", msg.message );
14406
14407 DestroyWindow(hwnd);
14408 DestroyWindow(hwnd2);
14409 }
14410
14411 static void test_unicode_wm_char(void)
14412 {
14413 HWND hwnd;
14414 MSG msg;
14415 struct message seq[2];
14416 HKL hkl_orig, hkl_greek;
14417 DWORD cp;
14418 LCID thread_locale;
14419
14420 hkl_orig = GetKeyboardLayout( 0 );
14421 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14422 if (cp != 1252)
14423 {
14424 skip( "Default codepage %d\n", cp );
14425 return;
14426 }
14427
14428 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14429 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14430 {
14431 skip( "Unable to load Greek keyboard layout\n" );
14432 return;
14433 }
14434
14435 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14436 100, 100, 200, 200, 0, 0, 0, NULL );
14437 flush_sequence();
14438
14439 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14440
14441 while (GetMessageW( &msg, hwnd, 0, 0 ))
14442 {
14443 if (!ignore_message( msg.message )) break;
14444 }
14445
14446 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14447 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14448 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14449 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14450
14451 DispatchMessageW( &msg );
14452
14453 memset( seq, 0, sizeof(seq) );
14454 seq[0].message = WM_CHAR;
14455 seq[0].flags = sent|wparam;
14456 seq[0].wParam = 0x3b1;
14457
14458 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14459
14460 flush_sequence();
14461
14462 /* greek alpha -> 'a' in cp1252 */
14463 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14464
14465 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14466 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14467 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14468 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
14469 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14470
14471 DispatchMessageA( &msg );
14472
14473 seq[0].wParam = 0x61;
14474 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14475
14476 thread_locale = GetThreadLocale();
14477 ActivateKeyboardLayout( hkl_greek, 0 );
14478 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14479 thread_locale, GetThreadLocale() );
14480
14481 flush_sequence();
14482
14483 /* greek alpha -> 0xe1 in cp1253 */
14484 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14485
14486 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14487 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14488 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14489 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14490 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14491
14492 DispatchMessageA( &msg );
14493
14494 seq[0].wParam = 0x3b1;
14495 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14496
14497 DestroyWindow( hwnd );
14498 ActivateKeyboardLayout( hkl_orig, 0 );
14499 UnloadKeyboardLayout( hkl_greek );
14500 }
14501
14502 #define ID_LISTBOX 0x000f
14503
14504 static const struct message wm_lb_setcursel_0[] =
14505 {
14506 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14507 { WM_CTLCOLORLISTBOX, sent|parent },
14508 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14509 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14510 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14511 { 0 }
14512 };
14513 static const struct message wm_lb_setcursel_1[] =
14514 {
14515 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14516 { WM_CTLCOLORLISTBOX, sent|parent },
14517 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14518 { WM_CTLCOLORLISTBOX, sent|parent },
14519 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14520 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14521 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14522 { 0 }
14523 };
14524 static const struct message wm_lb_setcursel_2[] =
14525 {
14526 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14527 { WM_CTLCOLORLISTBOX, sent|parent },
14528 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14529 { WM_CTLCOLORLISTBOX, sent|parent },
14530 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14531 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14532 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14533 { 0 }
14534 };
14535 static const struct message wm_lb_click_0[] =
14536 {
14537 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
14538 { HCBT_SETFOCUS, hook },
14539 { WM_KILLFOCUS, sent|parent },
14540 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
14541 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14542 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14543 { WM_SETFOCUS, sent|defwinproc },
14544
14545 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
14546 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
14547 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14548 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
14549 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14550
14551 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
14552 { WM_CTLCOLORLISTBOX, sent|parent },
14553 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
14554 { WM_CTLCOLORLISTBOX, sent|parent },
14555 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14556 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
14557
14558 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14559 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14560
14561 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
14562 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14563 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
14564 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
14565 { 0 }
14566 };
14567 static const struct message wm_lb_deletestring[] =
14568 {
14569 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14570 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14571 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14572 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14573 { 0 }
14574 };
14575 static const struct message wm_lb_deletestring_reset[] =
14576 {
14577 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14578 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
14579 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14580 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14581 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14582 { 0 }
14583 };
14584 static const struct message wm_lb_addstring[] =
14585 {
14586 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14587 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14588 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14589 { 0 }
14590 };
14591 static const struct message wm_lb_addstring_ownerdraw[] =
14592 {
14593 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14594 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14595 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14596 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14597 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14598 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14599 { 0 }
14600 };
14601 static const struct message wm_lb_addstring_sort_ownerdraw[] =
14602 {
14603 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14604 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14605 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14606 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
14607 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14608 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14609 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
14610 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
14611 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14612 { 0 }
14613 };
14614
14615 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
14616
14617 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
14618
14619 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14620 {
14621 static LONG defwndproc_counter = 0;
14622 LRESULT ret;
14623 struct recvd_message msg;
14624
14625 /* do not log painting messages */
14626 if (message != WM_PAINT &&
14627 message != WM_NCPAINT &&
14628 message != WM_SYNCPAINT &&
14629 message != WM_ERASEBKGND &&
14630 message != WM_NCHITTEST &&
14631 message != WM_GETTEXT &&
14632 !ignore_message( message ))
14633 {
14634 msg.hwnd = hwnd;
14635 msg.message = message;
14636 msg.flags = sent|wparam|lparam;
14637 if (defwndproc_counter) msg.flags |= defwinproc;
14638 msg.wParam = wp;
14639 if (message == LB_ADDSTRING)
14640 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
14641 else
14642 msg.lParam = lp;
14643 msg.descr = "listbox";
14644 add_message(&msg);
14645 }
14646
14647 defwndproc_counter++;
14648 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
14649 defwndproc_counter--;
14650
14651 return ret;
14652 }
14653
14654 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
14655 int caret_index, int top_index, int line)
14656 {
14657 LRESULT ret;
14658
14659 /* calling an orig proc helps to avoid unnecessary message logging */
14660 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14661 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14662 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14663 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14664 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14665 ok_(__FILE__, line)(ret == caret_index ||
14666 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
14667 "expected caret index %d, got %ld\n", caret_index, ret);
14668 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14669 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14670 }
14671
14672 static void test_listbox_messages(void)
14673 {
14674 HWND parent, listbox;
14675 LRESULT ret;
14676
14677 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14678 100, 100, 200, 200, 0, 0, 0, NULL);
14679 /* with LBS_HASSTRINGS */
14680 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14681 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14682 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14683 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14684
14685 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14686
14687 flush_sequence();
14688
14689 log_all_parent_messages++;
14690
14691 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14692 ok(ret == 0, "expected 0, got %ld\n", ret);
14693 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14694 ok(ret == 1, "expected 1, got %ld\n", ret);
14695 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14696 ok(ret == 2, "expected 2, got %ld\n", ret);
14697
14698 ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
14699 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14700
14701 flush_sequence();
14702
14703 trace("selecting item 0\n");
14704 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14705 ok(ret == 0, "expected 0, got %ld\n", ret);
14706 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14707 check_lb_state(listbox, 3, 0, 0, 0);
14708 flush_sequence();
14709
14710 trace("selecting item 1\n");
14711 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14712 ok(ret == 1, "expected 1, got %ld\n", ret);
14713 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14714 check_lb_state(listbox, 3, 1, 1, 0);
14715
14716 trace("selecting item 2\n");
14717 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14718 ok(ret == 2, "expected 2, got %ld\n", ret);
14719 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14720 check_lb_state(listbox, 3, 2, 2, 0);
14721
14722 trace("clicking on item 0\n");
14723 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14724 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14725 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14726 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14727 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14728 check_lb_state(listbox, 3, 0, 0, 0);
14729 flush_sequence();
14730
14731 trace("deleting item 0\n");
14732 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14733 ok(ret == 2, "expected 2, got %ld\n", ret);
14734 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14735 check_lb_state(listbox, 2, -1, 0, 0);
14736 flush_sequence();
14737
14738 trace("deleting item 0\n");
14739 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14740 ok(ret == 1, "expected 1, got %ld\n", ret);
14741 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14742 check_lb_state(listbox, 1, -1, 0, 0);
14743 flush_sequence();
14744
14745 trace("deleting item 0\n");
14746 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14747 ok(ret == 0, "expected 0, got %ld\n", ret);
14748 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14749 check_lb_state(listbox, 0, -1, 0, 0);
14750 flush_sequence();
14751
14752 trace("deleting item 0\n");
14753 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14754 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14755 check_lb_state(listbox, 0, -1, 0, 0);
14756 flush_sequence();
14757
14758 log_all_parent_messages--;
14759
14760 DestroyWindow(listbox);
14761
14762 /* with LBS_SORT and without LBS_HASSTRINGS */
14763 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14764 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
14765 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14766 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14767
14768 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14769
14770 flush_sequence();
14771
14772 log_all_parent_messages++;
14773
14774 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14775 ok(ret == 0, "expected 0, got %ld\n", ret);
14776 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14777 ok(ret == 1, "expected 1, got %ld\n", ret);
14778 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14779 ok(ret == 2, "expected 2, got %ld\n", ret);
14780
14781 ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
14782 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14783
14784 log_all_parent_messages--;
14785
14786 DestroyWindow(listbox);
14787
14788 /* with LBS_HASSTRINGS */
14789 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14790 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
14791 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14792 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14793
14794 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14795
14796 flush_sequence();
14797
14798 log_all_parent_messages++;
14799
14800 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14801 ok(ret == 0, "expected 0, got %ld\n", ret);
14802 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14803 ok(ret == 1, "expected 1, got %ld\n", ret);
14804 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14805 ok(ret == 2, "expected 2, got %ld\n", ret);
14806
14807 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
14808 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14809
14810 log_all_parent_messages--;
14811
14812 DestroyWindow(listbox);
14813
14814 /* with LBS_HASSTRINGS and LBS_SORT */
14815 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14816 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
14817 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14818 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14819
14820 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14821
14822 flush_sequence();
14823
14824 log_all_parent_messages++;
14825
14826 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14827 ok(ret == 0, "expected 0, got %ld\n", ret);
14828 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14829 ok(ret == 0, "expected 0, got %ld\n", ret);
14830 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14831 ok(ret == 1, "expected 1, got %ld\n", ret);
14832
14833 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
14834 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14835
14836 log_all_parent_messages--;
14837
14838 DestroyWindow(listbox);
14839 DestroyWindow(parent);
14840 }
14841
14842 /*************************** Menu test ******************************/
14843 static const struct message wm_popup_menu_1[] =
14844 {
14845 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14846 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14847 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
14848 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
14849 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
14850 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
14851 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14852 { WM_INITMENU, sent|lparam, 0, 0 },
14853 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
14854 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
14855 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
14856 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
14857 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
14858 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14859 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
14860 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
14861 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14862 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14863 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14864 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
14865 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14866 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14867 { 0 }
14868 };
14869 static const struct message wm_popup_menu_2[] =
14870 {
14871 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14872 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14873 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14874 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14875 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14876 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14877 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14878 { WM_INITMENU, sent|lparam, 0, 0 },
14879 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14880 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14881 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14882 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14883 { HCBT_CREATEWND, hook },
14884 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14885 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14886 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14887 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14888 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14889 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14890 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14891 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14892 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14893 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14894 { HCBT_DESTROYWND, hook },
14895 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14896 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14897 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14898 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14899 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14900 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
14901 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14902 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14903 { 0 }
14904 };
14905 static const struct message wm_popup_menu_3[] =
14906 {
14907 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14908 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14909 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14910 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14911 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14912 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14913 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14914 { WM_INITMENU, sent|lparam, 0, 0 },
14915 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14916 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14917 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14918 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14919 { HCBT_CREATEWND, hook },
14920 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14921 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14922 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14923 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14924 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14925 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14926 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14927 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14928 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14929 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14930 { HCBT_DESTROYWND, hook },
14931 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14932 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14933 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14934 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14935 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14936 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
14937 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14938 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14939 { 0 }
14940 };
14941
14942 static const struct message wm_single_menu_item[] =
14943 {
14944 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14945 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14946 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
14947 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
14948 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
14949 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
14950 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14951 { WM_INITMENU, sent|lparam, 0, 0 },
14952 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
14953 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14954 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14955 { WM_MENUCOMMAND, sent },
14956 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
14957 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
14958 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
14959 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
14960
14961 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
14962 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
14963 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
14964 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
14965 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
14966 { 0 }
14967 };
14968
14969 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14970 {
14971 if (message == WM_ENTERIDLE ||
14972 message == WM_INITMENU ||
14973 message == WM_INITMENUPOPUP ||
14974 message == WM_MENUSELECT ||
14975 message == WM_PARENTNOTIFY ||
14976 message == WM_ENTERMENULOOP ||
14977 message == WM_EXITMENULOOP ||
14978 message == WM_UNINITMENUPOPUP ||
14979 message == WM_KEYDOWN ||
14980 message == WM_KEYUP ||
14981 message == WM_CHAR ||
14982 message == WM_SYSKEYDOWN ||
14983 message == WM_SYSKEYUP ||
14984 message == WM_SYSCHAR ||
14985 message == WM_COMMAND ||
14986 message == WM_MENUCOMMAND)
14987 {
14988 struct recvd_message msg;
14989
14990 msg.hwnd = hwnd;
14991 msg.message = message;
14992 msg.flags = sent|wparam|lparam;
14993 msg.wParam = wp;
14994 msg.lParam = lp;
14995 msg.descr = "parent_menu_proc";
14996 add_message(&msg);
14997 }
14998
14999 return DefWindowProcA(hwnd, message, wp, lp);
15000 }
15001
15002 static void set_menu_style(HMENU hmenu, DWORD style)
15003 {
15004 MENUINFO mi;
15005 BOOL ret;
15006
15007 mi.cbSize = sizeof(mi);
15008 mi.fMask = MIM_STYLE;
15009 mi.dwStyle = style;
15010 SetLastError(0xdeadbeef);
15011 ret = pSetMenuInfo(hmenu, &mi);
15012 ok(ret, "SetMenuInfo error %u\n", GetLastError());
15013 }
15014
15015 static DWORD get_menu_style(HMENU hmenu)
15016 {
15017 MENUINFO mi;
15018 BOOL ret;
15019
15020 mi.cbSize = sizeof(mi);
15021 mi.fMask = MIM_STYLE;
15022 mi.dwStyle = 0;
15023 SetLastError(0xdeadbeef);
15024 ret = pGetMenuInfo(hmenu, &mi);
15025 ok(ret, "GetMenuInfo error %u\n", GetLastError());
15026
15027 return mi.dwStyle;
15028 }
15029
15030 static void test_menu_messages(void)
15031 {
15032 MSG msg;
15033 WNDCLASSA cls;
15034 HMENU hmenu, hmenu_popup;
15035 HWND hwnd;
15036 DWORD style;
15037
15038 if (!pGetMenuInfo || !pSetMenuInfo)
15039 {
15040 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
15041 return;
15042 }
15043 cls.style = 0;
15044 cls.lpfnWndProc = parent_menu_proc;
15045 cls.cbClsExtra = 0;
15046 cls.cbWndExtra = 0;
15047 cls.hInstance = GetModuleHandleA(0);
15048 cls.hIcon = 0;
15049 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15050 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15051 cls.lpszMenuName = NULL;
15052 cls.lpszClassName = "TestMenuClass";
15053 UnregisterClassA(cls.lpszClassName, cls.hInstance);
15054 if (!RegisterClassA(&cls)) assert(0);
15055
15056 SetLastError(0xdeadbeef);
15057 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15058 100, 100, 200, 200, 0, 0, 0, NULL);
15059 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
15060
15061 SetLastError(0xdeadbeef);
15062 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
15063 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
15064
15065 SetMenu(hwnd, hmenu);
15066 SetForegroundWindow( hwnd );
15067 flush_events();
15068
15069 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
15070 style = get_menu_style(hmenu);
15071 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15072
15073 hmenu_popup = GetSubMenu(hmenu, 0);
15074 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15075 style = get_menu_style(hmenu_popup);
15076 ok(style == 0, "expected 0, got %u\n", style);
15077
15078 hmenu_popup = GetSubMenu(hmenu_popup, 0);
15079 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15080 style = get_menu_style(hmenu_popup);
15081 ok(style == 0, "expected 0, got %u\n", style);
15082
15083 /* Alt+E, Enter */
15084 trace("testing a popup menu command\n");
15085 flush_sequence();
15086 keybd_event(VK_MENU, 0, 0, 0);
15087 keybd_event('E', 0, 0, 0);
15088 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
15089 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15090 keybd_event(VK_RETURN, 0, 0, 0);
15091 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15092 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15093 {
15094 TranslateMessage(&msg);
15095 DispatchMessageA(&msg);
15096 }
15097 if (!sequence_cnt) /* we didn't get any message */
15098 {
15099 skip( "queuing key events not supported\n" );
15100 goto done;
15101 }
15102 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
15103 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
15104 {
15105 win_skip( "menu tracking through VK_MENU not supported\n" );
15106 goto done;
15107 }
15108 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
15109
15110 /* Alt+F, Right, Enter */
15111 trace("testing submenu of a popup menu command\n");
15112 flush_sequence();
15113 keybd_event(VK_MENU, 0, 0, 0);
15114 keybd_event('F', 0, 0, 0);
15115 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15116 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15117 keybd_event(VK_RIGHT, 0, 0, 0);
15118 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15119 keybd_event(VK_RETURN, 0, 0, 0);
15120 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15121 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15122 {
15123 TranslateMessage(&msg);
15124 DispatchMessageA(&msg);
15125 }
15126 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
15127
15128 trace("testing single menu item command\n");
15129 flush_sequence();
15130 keybd_event(VK_MENU, 0, 0, 0);
15131 keybd_event('Q', 0, 0, 0);
15132 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
15133 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15134 keybd_event(VK_ESCAPE, 0, 0, 0);
15135 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
15136 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15137 {
15138 TranslateMessage(&msg);
15139 DispatchMessageA(&msg);
15140 }
15141 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
15142
15143 set_menu_style(hmenu, 0);
15144 style = get_menu_style(hmenu);
15145 ok(style == 0, "expected 0, got %u\n", style);
15146
15147 hmenu_popup = GetSubMenu(hmenu, 0);
15148 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15149 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
15150 style = get_menu_style(hmenu_popup);
15151 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15152
15153 hmenu_popup = GetSubMenu(hmenu_popup, 0);
15154 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15155 style = get_menu_style(hmenu_popup);
15156 ok(style == 0, "expected 0, got %u\n", style);
15157
15158 /* Alt+F, Right, Enter */
15159 trace("testing submenu of a popup menu command\n");
15160 flush_sequence();
15161 keybd_event(VK_MENU, 0, 0, 0);
15162 keybd_event('F', 0, 0, 0);
15163 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15164 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15165 keybd_event(VK_RIGHT, 0, 0, 0);
15166 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15167 keybd_event(VK_RETURN, 0, 0, 0);
15168 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15169 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15170 {
15171 TranslateMessage(&msg);
15172 DispatchMessageA(&msg);
15173 }
15174 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15175
15176 done:
15177 DestroyWindow(hwnd);
15178 DestroyMenu(hmenu);
15179 }
15180
15181
15182 static void test_paintingloop(void)
15183 {
15184 HWND hwnd;
15185
15186 paint_loop_done = FALSE;
15187 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15188 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15189 100, 100, 100, 100, 0, 0, 0, NULL );
15190 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15191 ShowWindow(hwnd,SW_NORMAL);
15192 SetFocus(hwnd);
15193
15194 while (!paint_loop_done)
15195 {
15196 MSG msg;
15197 if (PeekMessageA(&msg, 0, 0, 0, 1))
15198 {
15199 TranslateMessage(&msg);
15200 DispatchMessageA(&msg);
15201 }
15202 }
15203 DestroyWindow(hwnd);
15204 }
15205
15206 static const struct message NCRBUTTONDOWNSeq[] =
15207 {
15208 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15209 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15210 { WM_CAPTURECHANGED, sent },
15211 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15212 { 0 }
15213 };
15214
15215 static const struct message NCXBUTTONUPSeq1[] =
15216 {
15217 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15218 { 0 }
15219 };
15220
15221 static const struct message NCXBUTTONUPSeq2[] =
15222 {
15223 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15224 { 0 }
15225 };
15226
15227 struct rbuttonup_thread_data
15228 {
15229 HWND hwnd;
15230 HANDLE wndproc_finished;
15231 };
15232
15233 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15234 {
15235 struct rbuttonup_thread_data *data = arg;
15236 DWORD ret;
15237
15238 ret = WaitForSingleObject( data->wndproc_finished, 500 );
15239 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15240 if( ret == WAIT_OBJECT_0 ) return 0;
15241
15242 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15243 return 0;
15244 }
15245
15246 static void test_defwinproc(void)
15247 {
15248 HWND hwnd;
15249 MSG msg;
15250 BOOL gotwmquit = FALSE;
15251 POINT pos;
15252 RECT rect;
15253 INT x, y;
15254 LRESULT res;
15255 struct rbuttonup_thread_data data;
15256 char buffA[64];
15257 HANDLE thread;
15258
15259 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15260 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15261 assert(hwnd);
15262 flush_events();
15263
15264 buffA[0] = 0;
15265 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15266 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15267
15268 /* Zero high word of the lParam */
15269 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15270 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15271
15272 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15273 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15274
15275 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15276 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15277
15278 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15279 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15280
15281 GetCursorPos(&pos);
15282 GetWindowRect(hwnd, &rect);
15283 x = (rect.left+rect.right) / 2;
15284 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15285 SetCursorPos(x, y);
15286 flush_events();
15287 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15288 ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15289
15290 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15291 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15292 flush_events();
15293
15294 flush_sequence();
15295 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15296 /* workaround for missing support for clicking on window frame */
15297 data.hwnd = hwnd;
15298 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15299 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15300
15301 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15302 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15303
15304 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15305 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15306 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15307
15308 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15309 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15310 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15311
15312 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15313 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15314 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15315
15316 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15317 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15318 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15319
15320 SetEvent( data.wndproc_finished );
15321 WaitForSingleObject( thread, 1000 );
15322 CloseHandle( data.wndproc_finished );
15323 CloseHandle( thread );
15324
15325 SetCursorPos(pos.x, pos.y);
15326
15327 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15328 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15329 if( msg.message == WM_QUIT) gotwmquit = TRUE;
15330 DispatchMessageA( &msg );
15331 }
15332 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15333 DestroyWindow( hwnd);
15334 }
15335
15336 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
15337 static void clear_clipboard_(int line, HWND hWnd)
15338 {
15339 BOOL succ;
15340 succ = OpenClipboard(hWnd);
15341 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15342 succ = EmptyClipboard();
15343 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15344 succ = CloseClipboard();
15345 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15346 }
15347
15348 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
15349 static void expect_HWND_(int line, HWND expected, HWND got)
15350 {
15351 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
15352 }
15353
15354 static WNDPROC pOldViewerProc;
15355
15356 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
15357 {
15358 static BOOL recursion_guard;
15359
15360 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
15361 {
15362 recursion_guard = TRUE;
15363 clear_clipboard(hWnd);
15364 recursion_guard = FALSE;
15365 }
15366 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
15367 }
15368
15369 static void test_clipboard_viewers(void)
15370 {
15371 static struct message wm_change_cb_chain[] =
15372 {
15373 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
15374 { 0 }
15375 };
15376 static const struct message wm_clipboard_destroyed[] =
15377 {
15378 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15379 { 0 }
15380 };
15381 static struct message wm_clipboard_changed[] =
15382 {
15383 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15384 { 0 }
15385 };
15386 static struct message wm_clipboard_changed_and_owned[] =
15387 {
15388 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15389 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15390 { 0 }
15391 };
15392
15393 HINSTANCE hInst = GetModuleHandleA(NULL);
15394 HWND hWnd1, hWnd2, hWnd3;
15395 HWND hOrigViewer;
15396 HWND hRet;
15397
15398 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
15399 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15400 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15401 GetDesktopWindow(), NULL, hInst, NULL);
15402 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
15403 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15404 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15405 GetDesktopWindow(), NULL, hInst, NULL);
15406 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
15407 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15408 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15409 GetDesktopWindow(), NULL, hInst, NULL);
15410 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
15411 assert(hWnd1 && hWnd2 && hWnd3);
15412
15413 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
15414 flush_sequence();
15415
15416 /* Test getting the clipboard viewer and setting the viewer to NULL. */
15417 hOrigViewer = GetClipboardViewer();
15418 hRet = SetClipboardViewer(NULL);
15419 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
15420 expect_HWND(hOrigViewer, hRet);
15421 expect_HWND(NULL, GetClipboardViewer());
15422
15423 /* Test registering hWnd1 as a viewer. */
15424 hRet = SetClipboardViewer(hWnd1);
15425 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15426 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
15427 expect_HWND(NULL, hRet);
15428 expect_HWND(hWnd1, GetClipboardViewer());
15429
15430 /* Test that changing the clipboard actually refreshes the registered viewer. */
15431 clear_clipboard(hWnd1);
15432 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15433 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
15434
15435 /* Again, but with different owner. */
15436 clear_clipboard(hWnd2);
15437 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
15438 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
15439
15440 /* Test re-registering same window. */
15441 hRet = SetClipboardViewer(hWnd1);
15442 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15443 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
15444 expect_HWND(hWnd1, hRet);
15445 expect_HWND(hWnd1, GetClipboardViewer());
15446
15447 /* Test ChangeClipboardChain. */
15448 ChangeClipboardChain(hWnd2, hWnd3);
15449 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15450 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
15451 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
15452 expect_HWND(hWnd1, GetClipboardViewer());
15453
15454 ChangeClipboardChain(hWnd2, NULL);
15455 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15456 wm_change_cb_chain[0].lParam = 0;
15457 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
15458 expect_HWND(hWnd1, GetClipboardViewer());
15459
15460 ChangeClipboardChain(NULL, hWnd2);
15461 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
15462 expect_HWND(hWnd1, GetClipboardViewer());
15463
15464 /* Actually change clipboard viewer with ChangeClipboardChain. */
15465 ChangeClipboardChain(hWnd1, hWnd2);
15466 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
15467 expect_HWND(hWnd2, GetClipboardViewer());
15468
15469 /* Test that no refresh messages are sent when viewer has unregistered. */
15470 clear_clipboard(hWnd2);
15471 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
15472
15473 /* Register hWnd1 again. */
15474 ChangeClipboardChain(hWnd2, hWnd1);
15475 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
15476 expect_HWND(hWnd1, GetClipboardViewer());
15477
15478 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
15479 * changes the clipboard. When this happens, the system shouldn't send
15480 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
15481 */
15482 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
15483 clear_clipboard(hWnd2);
15484 /* The clipboard owner is changed in recursive_viewer_proc: */
15485 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
15486 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
15487
15488 /* Test unregistering. */
15489 ChangeClipboardChain(hWnd1, NULL);
15490 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
15491 expect_HWND(NULL, GetClipboardViewer());
15492
15493 clear_clipboard(hWnd1);
15494 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
15495
15496 DestroyWindow(hWnd1);
15497 DestroyWindow(hWnd2);
15498 DestroyWindow(hWnd3);
15499 SetClipboardViewer(hOrigViewer);
15500 }
15501
15502 static void test_PostMessage(void)
15503 {
15504 static const struct
15505 {
15506 HWND hwnd;
15507 BOOL ret;
15508 } data[] =
15509 {
15510 { HWND_TOP /* 0 */, TRUE },
15511 { HWND_BROADCAST, TRUE },
15512 { HWND_BOTTOM, TRUE },
15513 { HWND_TOPMOST, TRUE },
15514 { HWND_NOTOPMOST, FALSE },
15515 { HWND_MESSAGE, FALSE },
15516 { (HWND)0xdeadbeef, FALSE }
15517 };
15518 int i;
15519 HWND hwnd;
15520 BOOL ret;
15521 MSG msg;
15522 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
15523
15524 SetLastError(0xdeadbeef);
15525 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
15526 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
15527 {
15528 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
15529 return;
15530 }
15531 assert(hwnd);
15532
15533 flush_events();
15534
15535 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
15536 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
15537
15538 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
15539 {
15540 memset(&msg, 0xab, sizeof(msg));
15541 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
15542 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
15543 if (data[i].ret)
15544 {
15545 if (data[i].hwnd)
15546 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
15547 msg.wParam == 0x5678 && msg.lParam == 0x1234,
15548 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
15549 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
15550 else
15551 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
15552 msg.wParam == 0x1234 && msg.lParam == 0x5678,
15553 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
15554 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
15555 }
15556 }
15557
15558 DestroyWindow(hwnd);
15559 flush_events();
15560 }
15561
15562 static LPARAM g_broadcast_lparam;
15563 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15564 {
15565 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
15566
15567 if (wParam == 0xbaadbeef)
15568 g_broadcast_lparam = wParam;
15569 else
15570 g_broadcast_lparam = 0;
15571
15572 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
15573 }
15574
15575 static void test_broadcast(void)
15576 {
15577 static const UINT messages[] =
15578 {
15579 WM_USER-1,
15580 WM_USER,
15581 WM_USER+1,
15582 0xc000-1,
15583 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
15584 0xffff,
15585 };
15586 WNDPROC oldproc;
15587 unsigned int i;
15588 HWND hwnd;
15589
15590 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
15591 ok(hwnd != NULL, "got %p\n", hwnd);
15592
15593 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
15594 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
15595
15596 for (i = 0; i < sizeof(messages)/sizeof(messages[0]); i++)
15597 {
15598 BOOL ret;
15599 MSG msg;
15600
15601 flush_events();
15602 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15603 ;
15604
15605 /* post, broadcast */
15606 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
15607 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15608
15609 memset(&msg, 0xab, sizeof(msg));
15610 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15611 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15612 {
15613 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15614 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15615 }
15616 else
15617 {
15618 ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15619 }
15620
15621 /* post, topmost */
15622 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
15623 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15624
15625 memset(&msg, 0xab, sizeof(msg));
15626 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15627 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15628 {
15629 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15630 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15631 }
15632 else
15633 {
15634 ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15635 }
15636
15637 /* send, broadcast */
15638 g_broadcast_lparam = 0xdead;
15639 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15640 if (!ret && GetLastError() == ERROR_TIMEOUT)
15641 win_skip("broadcasting test %d, timeout\n", i);
15642 else
15643 {
15644 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15645 {
15646 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15647 g_broadcast_lparam, GetLastError());
15648 }
15649 else
15650 {
15651 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15652 g_broadcast_lparam, GetLastError());
15653 }
15654 }
15655
15656 /* send, topmost */
15657 g_broadcast_lparam = 0xdead;
15658 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15659 if (!ret && GetLastError() == ERROR_TIMEOUT)
15660 win_skip("broadcasting test %d, timeout\n", i);
15661 else
15662 {
15663 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15664 {
15665 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15666 g_broadcast_lparam, GetLastError());
15667 }
15668 else
15669 {
15670 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15671 g_broadcast_lparam, GetLastError());
15672 }
15673 }
15674 }
15675
15676 DestroyWindow(hwnd);
15677 }
15678
15679 static const struct
15680 {
15681 DWORD exp, broken;
15682 BOOL todo;
15683 } wait_idle_expect[] =
15684 {
15685 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15686 { WAIT_TIMEOUT, 0, FALSE },
15687 { WAIT_TIMEOUT, 0, FALSE },
15688 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15689 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15690 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
15691 { WAIT_TIMEOUT, 0, FALSE },
15692 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15693 { 0, 0, FALSE },
15694 { 0, 0, FALSE },
15695 /* 10 */ { 0, 0, FALSE },
15696 { 0, 0, FALSE },
15697 { 0, WAIT_TIMEOUT, FALSE },
15698 { 0, 0, FALSE },
15699 { 0, 0, FALSE },
15700 /* 15 */ { 0, 0, FALSE },
15701 { WAIT_TIMEOUT, 0, FALSE },
15702 { WAIT_TIMEOUT, 0, FALSE },
15703 { WAIT_TIMEOUT, 0, FALSE },
15704 { WAIT_TIMEOUT, 0, FALSE },
15705 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
15706 };
15707
15708 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
15709 {
15710 MSG msg;
15711
15712 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15713 Sleep( 200 );
15714 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15715 return 0;
15716 }
15717
15718 static void do_wait_idle_child( int arg )
15719 {
15720 WNDCLASSA cls;
15721 MSG msg;
15722 HWND hwnd = 0;
15723 HANDLE thread;
15724 DWORD id;
15725 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
15726 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
15727
15728 memset( &cls, 0, sizeof(cls) );
15729 cls.lpfnWndProc = DefWindowProcA;
15730 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15731 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15732 cls.lpszClassName = "TestClass";
15733 RegisterClassA( &cls );
15734
15735 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
15736
15737 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
15738 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
15739
15740 switch (arg)
15741 {
15742 case 0:
15743 SetEvent( start_event );
15744 break;
15745 case 1:
15746 SetEvent( start_event );
15747 Sleep( 200 );
15748 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15749 break;
15750 case 2:
15751 SetEvent( start_event );
15752 Sleep( 200 );
15753 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15754 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
15755 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15756 break;
15757 case 3:
15758 SetEvent( start_event );
15759 Sleep( 200 );
15760 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
15761 break;
15762 case 4:
15763 SetEvent( start_event );
15764 Sleep( 200 );
15765 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15766 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15767 break;
15768 case 5:
15769 SetEvent( start_event );
15770 Sleep( 200 );
15771 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15772 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15773 break;
15774 case 6:
15775 SetEvent( start_event );
15776 Sleep( 200 );
15777 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15778 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
15779 {
15780 GetMessageA( &msg, 0, 0, 0 );
15781 DispatchMessageA( &msg );
15782 }
15783 break;
15784 case 7:
15785 SetEvent( start_event );
15786 Sleep( 200 );
15787 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15788 SetTimer( hwnd, 3, 1, NULL );
15789 Sleep( 200 );
15790 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15791 break;
15792 case 8:
15793 SetEvent( start_event );
15794 Sleep( 200 );
15795 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15796 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15797 break;
15798 case 9:
15799 SetEvent( start_event );
15800 Sleep( 200 );
15801 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15802 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15803 for (;;) GetMessageA( &msg, 0, 0, 0 );
15804 break;
15805 case 10:
15806 SetEvent( start_event );
15807 Sleep( 200 );
15808 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15809 SetTimer( hwnd, 3, 1, NULL );
15810 Sleep( 200 );
15811 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15812 break;
15813 case 11:
15814 SetEvent( start_event );
15815 Sleep( 200 );
15816 return; /* exiting the process makes WaitForInputIdle return success too */
15817 case 12:
15818 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15819 Sleep( 200 );
15820 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15821 SetEvent( start_event );
15822 break;
15823 case 13:
15824 SetEvent( start_event );
15825 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15826 Sleep( 200 );
15827 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
15828 WaitForSingleObject( thread, 10000 );
15829 CloseHandle( thread );
15830 break;
15831 case 14:
15832 SetEvent( start_event );
15833 Sleep( 200 );
15834 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
15835 break;
15836 case 15:
15837 SetEvent( start_event );
15838 Sleep( 200 );
15839 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
15840 break;
15841 case 16:
15842 SetEvent( start_event );
15843 Sleep( 200 );
15844 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
15845 break;
15846 case 17:
15847 SetEvent( start_event );
15848 Sleep( 200 );
15849 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
15850 break;
15851 case 18:
15852 SetEvent( start_event );
15853 Sleep( 200 );
15854 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
15855 break;
15856 case 19:
15857 SetEvent( start_event );
15858 Sleep( 200 );
15859 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
15860 break;
15861 case 20:
15862 SetEvent( start_event );
15863 Sleep( 200 );
15864 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
15865 break;
15866 }
15867 WaitForSingleObject( end_event, 2000 );
15868 CloseHandle( start_event );
15869 CloseHandle( end_event );
15870 if (hwnd) DestroyWindow( hwnd );
15871 }
15872
15873 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
15874 {
15875 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
15876 return DefWindowProcA( hwnd, msg, wp, lp );
15877 }
15878
15879 static DWORD CALLBACK wait_idle_thread( void *arg )
15880 {
15881 WNDCLASSA cls;
15882 MSG msg;
15883 HWND hwnd;
15884
15885 memset( &cls, 0, sizeof(cls) );
15886 cls.lpfnWndProc = wait_idle_proc;
15887 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15888 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15889 cls.lpszClassName = "TestClass";
15890 RegisterClassA( &cls );
15891
15892 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
15893 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
15894 DestroyWindow(hwnd);
15895 return 0;
15896 }
15897
15898 static void test_WaitForInputIdle( char *argv0 )
15899 {
15900 char path[MAX_PATH];
15901 PROCESS_INFORMATION pi;
15902 STARTUPINFOA startup;
15903 BOOL ret;
15904 HANDLE start_event, end_event, thread;
15905 unsigned int i;
15906 DWORD id;
15907 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
15908 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
15909 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
15910
15911 if (console_app) /* build the test with -mwindows for better coverage */
15912 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
15913
15914 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
15915 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
15916 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
15917 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
15918
15919 memset( &startup, 0, sizeof(startup) );
15920 startup.cb = sizeof(startup);
15921 startup.dwFlags = STARTF_USESHOWWINDOW;
15922 startup.wShowWindow = SW_SHOWNORMAL;
15923
15924 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
15925
15926 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
15927 {
15928 ResetEvent( start_event );
15929 ResetEvent( end_event );
15930 #ifndef __REACTOS__
15931 sprintf( path, "%s msg %u", argv0, i );
15932 #else
15933 sprintf( path, "%s msg_queue %u", argv0, i );
15934 #endif
15935 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
15936 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
15937 if (ret)
15938 {
15939 ret = WaitForSingleObject( start_event, 5000 );
15940 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
15941 if (ret == WAIT_OBJECT_0)
15942 {
15943 ret = WaitForInputIdle( pi.hProcess, 1000 );
15944 if (ret == WAIT_FAILED)
15945 ok( console_app ||
15946 ret == wait_idle_expect[i].exp ||
15947 broken(ret == wait_idle_expect[i].broken),
15948 "%u: WaitForInputIdle error %08x expected %08x\n",
15949 i, ret, wait_idle_expect[i].exp );
15950 else todo_wine_if (wait_idle_expect[i].todo)
15951 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
15952 "%u: WaitForInputIdle error %08x expected %08x\n",
15953 i, ret, wait_idle_expect[i].exp );
15954 SetEvent( end_event );
15955 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
15956 }
15957 TerminateProcess( pi.hProcess, 0 ); /* just in case */
15958 winetest_wait_child_process( pi.hProcess );
15959 ret = WaitForInputIdle( pi.hProcess, 100 );
15960 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
15961 CloseHandle( pi.hProcess );
15962 CloseHandle( pi.hThread );
15963 }
15964 }
15965 CloseHandle( start_event );
15966 PostThreadMessageA( id, WM_QUIT, 0, 0 );
15967 WaitForSingleObject( thread, 10000 );
15968 CloseHandle( thread );
15969 }
15970
15971 static const struct message WmSetParentSeq_1[] = {
15972 { WM_SHOWWINDOW, sent|wparam, 0 },
15973 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15974 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15975 { WM_CHILDACTIVATE, sent },
15976 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
15977 { WM_MOVE, sent|defwinproc|wparam, 0 },
15978 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15979 { WM_SHOWWINDOW, sent|wparam, 1 },
15980 { 0 }
15981 };
15982
15983 static const struct message WmSetParentSeq_2[] = {
15984 { WM_SHOWWINDOW, sent|wparam, 0 },
15985 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15986 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15987 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15988 { HCBT_SETFOCUS, hook|optional },
15989 { WM_NCACTIVATE, sent|wparam|optional, 0 },
15990 { WM_ACTIVATE, sent|wparam|optional, 0 },
15991 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15992 { WM_KILLFOCUS, sent|wparam, 0 },
15993 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15994 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15995 { HCBT_ACTIVATE, hook|optional },
15996 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
15997 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15998 { WM_NCACTIVATE, sent|wparam|optional, 1 },
15999 { WM_ACTIVATE, sent|wparam|optional, 1 },
16000 { HCBT_SETFOCUS, hook|optional },
16001 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16002 { WM_SETFOCUS, sent|optional|defwinproc },
16003 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
16004 { WM_MOVE, sent|defwinproc|wparam, 0 },
16005 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16006 { WM_SHOWWINDOW, sent|wparam, 1 },
16007 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16008 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
16009 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16010 { 0 }
16011 };
16012
16013
16014 static void test_SetParent(void)
16015 {
16016 HWND parent1, parent2, child, popup;
16017 RECT rc, rc_old;
16018
16019 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16020 100, 100, 200, 200, 0, 0, 0, NULL);
16021 ok(parent1 != 0, "Failed to create parent1 window\n");
16022
16023 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16024 400, 100, 200, 200, 0, 0, 0, NULL);
16025 ok(parent2 != 0, "Failed to create parent2 window\n");
16026
16027 /* WS_CHILD window */
16028 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
16029 10, 10, 150, 150, parent1, 0, 0, NULL);
16030 ok(child != 0, "Failed to create child window\n");
16031
16032 GetWindowRect(parent1, &rc);
16033 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
16034 GetWindowRect(child, &rc_old);
16035 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
16036 trace("child %s\n", wine_dbgstr_rect(&rc_old));
16037
16038 flush_sequence();
16039
16040 SetParent(child, parent2);
16041 flush_events();
16042 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
16043
16044 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16045 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
16046
16047 GetWindowRect(parent2, &rc);
16048 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16049 GetWindowRect(child, &rc);
16050 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
16051 trace("child %s\n", wine_dbgstr_rect(&rc));
16052
16053 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16054 wine_dbgstr_rect(&rc));
16055
16056 /* WS_POPUP window */
16057 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
16058 20, 20, 100, 100, 0, 0, 0, NULL);
16059 ok(popup != 0, "Failed to create popup window\n");
16060
16061 GetWindowRect(popup, &rc_old);
16062 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
16063
16064 flush_sequence();
16065
16066 SetParent(popup, child);
16067 flush_events();
16068 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
16069
16070 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16071 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
16072
16073 GetWindowRect(child, &rc);
16074 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16075 GetWindowRect(popup, &rc);
16076 MapWindowPoints(0, child, (POINT *)&rc, 2);
16077 trace("popup %s\n", wine_dbgstr_rect(&rc));
16078
16079 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16080 wine_dbgstr_rect(&rc));
16081
16082 DestroyWindow(popup);
16083 DestroyWindow(child);
16084 DestroyWindow(parent1);
16085 DestroyWindow(parent2);
16086
16087 flush_sequence();
16088 }
16089
16090 static const struct message WmKeyReleaseOnly[] = {
16091 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
16092 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
16093 { 0 }
16094 };
16095 static const struct message WmKeyPressNormal[] = {
16096 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
16097 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
16098 { 0 }
16099 };
16100 static const struct message WmKeyPressRepeat[] = {
16101 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
16102 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
16103 { 0 }
16104 };
16105 static const struct message WmKeyReleaseNormal[] = {
16106 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
16107 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
16108 { 0 }
16109 };
16110
16111 static void test_keyflags(void)
16112 {
16113 HWND test_window;
16114 SHORT key_state;
16115 BYTE keyboard_state[256];
16116 MSG msg;
16117
16118 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16119 100, 100, 200, 200, 0, 0, 0, NULL);
16120
16121 flush_events();
16122 flush_sequence();
16123
16124 /* keyup without a keydown */
16125 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16126 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16127 DispatchMessageA(&msg);
16128 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
16129
16130 key_state = GetAsyncKeyState(0x41);
16131 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16132
16133 key_state = GetKeyState(0x41);
16134 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16135
16136 /* keydown */
16137 keybd_event(0x41, 0, 0, 0);
16138 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16139 DispatchMessageA(&msg);
16140 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
16141
16142 key_state = GetAsyncKeyState(0x41);
16143 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16144
16145 key_state = GetKeyState(0x41);
16146 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16147
16148 /* keydown repeat */
16149 keybd_event(0x41, 0, 0, 0);
16150 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16151 DispatchMessageA(&msg);
16152 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
16153
16154 key_state = GetAsyncKeyState(0x41);
16155 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16156
16157 key_state = GetKeyState(0x41);
16158 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16159
16160 /* keyup */
16161 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16162 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16163 DispatchMessageA(&msg);
16164 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
16165
16166 key_state = GetAsyncKeyState(0x41);
16167 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16168
16169 key_state = GetKeyState(0x41);
16170 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16171
16172 /* set the key state in this thread */
16173 GetKeyboardState(keyboard_state);
16174 keyboard_state[0x41] = 0x80;
16175 SetKeyboardState(keyboard_state);
16176
16177 key_state = GetAsyncKeyState(0x41);
16178 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16179
16180 /* keydown */
16181 keybd_event(0x41, 0, 0, 0);
16182 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16183 DispatchMessageA(&msg);
16184 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16185
16186 key_state = GetAsyncKeyState(0x41);
16187 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16188
16189 key_state = GetKeyState(0x41);
16190 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16191
16192 /* clear the key state in this thread */
16193 GetKeyboardState(keyboard_state);
16194 keyboard_state[0x41] = 0;
16195 SetKeyboardState(keyboard_state);
16196
16197 key_state = GetAsyncKeyState(0x41);
16198 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16199
16200 /* keyup */
16201 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16202 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16203 DispatchMessageA(&msg);
16204 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16205
16206 key_state = GetAsyncKeyState(0x41);
16207 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16208
16209 key_state = GetKeyState(0x41);
16210 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16211
16212 DestroyWindow(test_window);
16213 flush_sequence();
16214 }
16215
16216 static const struct message WmHotkeyPressLWIN[] = {
16217 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16218 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16219 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16220 { 0 }
16221 };
16222 static const struct message WmHotkeyPress[] = {
16223 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16224 { WM_HOTKEY, sent|wparam, 5 },
16225 { 0 }
16226 };
16227 static const struct message WmHotkeyRelease[] = {
16228 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16229 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16230 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16231 { 0 }
16232 };
16233 static const struct message WmHotkeyReleaseLWIN[] = {
16234 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16235 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16236 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16237 { 0 }
16238 };
16239 static const struct message WmHotkeyCombined[] = {
16240 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16241 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16242 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16243 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16244 { WM_APP, sent, 0, 0 },
16245 { WM_HOTKEY, sent|wparam, 5 },
16246 { WM_APP+1, sent, 0, 0 },
16247 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16248 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16249 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16250 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16251 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16252 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16253 { 0 }
16254 };
16255 static const struct message WmHotkeyPrevious[] = {
16256 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16257 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16258 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16259 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16260 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16261 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16262 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16263 { WM_KEYDOWN, sent|lparam, 0, 1 },
16264 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16265 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16266 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16267 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16268 { 0 }
16269 };
16270 static const struct message WmHotkeyNew[] = {
16271 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16272 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16273 { WM_HOTKEY, sent|wparam, 5 },
16274 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16275 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16276 { 0 }
16277 };
16278
16279 static int hotkey_letter;
16280
16281 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16282 {
16283 struct recvd_message msg;
16284
16285 if (nCode == HC_ACTION)
16286 {
16287 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16288
16289 msg.hwnd = 0;
16290 msg.message = wParam;
16291 msg.flags = kbd_hook|wparam|lparam;
16292 msg.wParam = kdbhookstruct->vkCode;
16293 msg.lParam = kdbhookstruct->flags;
16294 msg.descr = "KeyboardHookProc";
16295 add_message(&msg);
16296
16297 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16298 {
16299 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
16300 "unexpected keycode %x\n", kdbhookstruct->vkCode);
16301 }
16302 }
16303
16304 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
16305 }
16306
16307 static void test_hotkey(void)
16308 {
16309 HWND test_window, taskbar_window;
16310 BOOL ret;
16311 MSG msg;
16312 DWORD queue_status;
16313 SHORT key_state;
16314
16315 SetLastError(0xdeadbeef);
16316 ret = UnregisterHotKey(NULL, 0);
16317 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16318 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16319 "unexpected error %d\n", GetLastError());
16320
16321 if (ret == TRUE)
16322 {
16323 skip("hotkeys not supported\n");
16324 return;
16325 }
16326
16327 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16328 100, 100, 200, 200, 0, 0, 0, NULL);
16329
16330 flush_sequence();
16331
16332 SetLastError(0xdeadbeef);
16333 ret = UnregisterHotKey(test_window, 0);
16334 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16335 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16336 "unexpected error %d\n", GetLastError());
16337
16338 /* Search for a Windows Key + letter combination that hasn't been registered */
16339 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
16340 {
16341 SetLastError(0xdeadbeef);
16342 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16343
16344 if (ret == TRUE)
16345 {
16346 break;
16347 }
16348 else
16349 {
16350 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16351 "unexpected error %d\n", GetLastError());
16352 }
16353 }
16354
16355 if (hotkey_letter == 0x52)
16356 {
16357 ok(0, "Couldn't find any free Windows Key + letter combination\n");
16358 goto end;
16359 }
16360
16361 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
16362 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
16363
16364 /* Same key combination, different id */
16365 SetLastError(0xdeadbeef);
16366 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
16367 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16368 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16369 "unexpected error %d\n", GetLastError());
16370
16371 /* Same key combination, different window */
16372 SetLastError(0xdeadbeef);
16373 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16374 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16375 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16376 "unexpected error %d\n", GetLastError());
16377
16378 /* Register the same hotkey twice */
16379 SetLastError(0xdeadbeef);
16380 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16381 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16382 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16383 "unexpected error %d\n", GetLastError());
16384
16385 /* Window on another thread */
16386 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
16387 if (!taskbar_window)
16388 {
16389 skip("no taskbar?\n");
16390 }
16391 else
16392 {
16393 SetLastError(0xdeadbeef);
16394 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
16395 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16396 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
16397 "unexpected error %d\n", GetLastError());
16398 }
16399
16400 /* Inject the appropriate key sequence */
16401 keybd_event(VK_LWIN, 0, 0, 0);
16402 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16403 DispatchMessageA(&msg);
16404 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
16405
16406 keybd_event(hotkey_letter, 0, 0, 0);
16407 queue_status = GetQueueStatus(QS_HOTKEY);
16408 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16409 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16410 {
16411 if (msg.message == WM_HOTKEY)
16412 {
16413 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16414 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16415 }
16416 DispatchMessageA(&msg);
16417 }
16418 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
16419
16420 queue_status = GetQueueStatus(QS_HOTKEY);
16421 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
16422
16423 key_state = GetAsyncKeyState(hotkey_letter);
16424 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16425
16426 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16427 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16428 DispatchMessageA(&msg);
16429 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
16430
16431 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16432 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16433 DispatchMessageA(&msg);
16434 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
16435
16436 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
16437 PostMessageA(test_window, WM_HOTKEY, 0, 0);
16438 queue_status = GetQueueStatus(QS_HOTKEY);
16439 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16440 queue_status = GetQueueStatus(QS_POSTMESSAGE);
16441 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
16442 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16443 DispatchMessageA(&msg);
16444 flush_sequence();
16445
16446 /* Send and process all messages at once */
16447 PostMessageA(test_window, WM_APP, 0, 0);
16448 keybd_event(VK_LWIN, 0, 0, 0);
16449 keybd_event(hotkey_letter, 0, 0, 0);
16450 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16451 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16452
16453 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16454 {
16455 if (msg.message == WM_HOTKEY)
16456 {
16457 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16458 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16459 }
16460 DispatchMessageA(&msg);
16461 }
16462 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
16463
16464 /* Register same hwnd/id with different key combination */
16465 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
16466 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16467
16468 /* Previous key combination does not work */
16469 keybd_event(VK_LWIN, 0, 0, 0);
16470 keybd_event(hotkey_letter, 0, 0, 0);
16471 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16472 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16473
16474 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16475 DispatchMessageA(&msg);
16476 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
16477
16478 /* New key combination works */
16479 keybd_event(hotkey_letter, 0, 0, 0);
16480 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16481
16482 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16483 {
16484 if (msg.message == WM_HOTKEY)
16485 {
16486 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16487 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16488 }
16489 DispatchMessageA(&msg);
16490 }
16491 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
16492
16493 /* Unregister hotkey properly */
16494 ret = UnregisterHotKey(test_window, 5);
16495 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16496
16497 /* Unregister hotkey again */
16498 SetLastError(0xdeadbeef);
16499 ret = UnregisterHotKey(test_window, 5);
16500 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16501 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16502 "unexpected error %d\n", GetLastError());
16503
16504 /* Register thread hotkey */
16505 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16506 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16507
16508 /* Inject the appropriate key sequence */
16509 keybd_event(VK_LWIN, 0, 0, 0);
16510 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16511 {
16512 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16513 DispatchMessageA(&msg);
16514 }
16515 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
16516
16517 keybd_event(hotkey_letter, 0, 0, 0);
16518 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16519 {
16520 if (msg.message == WM_HOTKEY)
16521 {
16522 struct recvd_message message;
16523 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
16524 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16525 message.message = msg.message;
16526 message.flags = sent|wparam|lparam;
16527 message.wParam = msg.wParam;
16528 message.lParam = msg.lParam;
16529 message.descr = "test_hotkey thread message";
16530 add_message(&message);
16531 }
16532 else
16533 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16534 DispatchMessageA(&msg);
16535 }
16536 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
16537
16538 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16539 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16540 {
16541 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16542 DispatchMessageA(&msg);
16543 }
16544 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
16545
16546 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16547 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16548 {
16549 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16550 DispatchMessageA(&msg);
16551 }
16552 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
16553
16554 /* Unregister thread hotkey */
16555 ret = UnregisterHotKey(NULL, 5);
16556 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16557
16558 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
16559 hKBD_hook = NULL;
16560
16561 end:
16562 UnregisterHotKey(NULL, 5);
16563 UnregisterHotKey(test_window, 5);
16564 DestroyWindow(test_window);
16565 flush_sequence();
16566 }
16567
16568
16569 static const struct message WmSetFocus_1[] = {
16570 { HCBT_SETFOCUS, hook }, /* child */
16571 { HCBT_ACTIVATE, hook }, /* parent */
16572 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
16573 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
16574 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
16575 { WM_NCACTIVATE, sent|parent },
16576 { WM_GETTEXT, sent|defwinproc|parent|optional },
16577 { WM_GETTEXT, sent|defwinproc|parent|optional },
16578 { WM_ACTIVATE, sent|wparam|parent, 1 },
16579 { HCBT_SETFOCUS, hook }, /* parent */
16580 { WM_SETFOCUS, sent|defwinproc|parent },
16581 { WM_KILLFOCUS, sent|parent },
16582 { WM_SETFOCUS, sent },
16583 { 0 }
16584 };
16585 static const struct message WmSetFocus_2[] = {
16586 { HCBT_SETFOCUS, hook }, /* parent */
16587 { WM_KILLFOCUS, sent },
16588 { WM_SETFOCUS, sent|parent },
16589 { 0 }
16590 };
16591 static const struct message WmSetFocus_3[] = {
16592 { HCBT_SETFOCUS, hook }, /* child */
16593 { 0 }
16594 };
16595
16596 static void test_SetFocus(void)
16597 {
16598 HWND parent, old_parent, child, old_focus, old_active;
16599 MSG msg;
16600 struct wnd_event wnd_event;
16601 HANDLE hthread;
16602 DWORD ret, tid;
16603
16604 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
16605 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
16606 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
16607 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
16608 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
16609 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16610 CloseHandle(wnd_event.start_event);
16611
16612 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16613 0, 0, 0, 0, 0, 0, 0, NULL);
16614 ok(parent != 0, "failed to create parent window\n");
16615 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
16616 0, 0, 0, 0, parent, 0, 0, NULL);
16617 ok(child != 0, "failed to create child window\n");
16618
16619 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
16620
16621 SetFocus(0);
16622 SetActiveWindow(0);
16623
16624 flush_events();
16625 flush_sequence();
16626
16627 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16628 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16629
16630 log_all_parent_messages++;
16631
16632 old_focus = SetFocus(child);
16633 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16634 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
16635 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16636 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16637 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
16638
16639 old_focus = SetFocus(parent);
16640 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16641 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
16642 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
16643 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16644 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16645
16646 SetLastError(0xdeadbeef);
16647 old_focus = SetFocus((HWND)0xdeadbeef);
16648 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16649 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16650 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16651 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
16652 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16653 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16654 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16655
16656 SetLastError(0xdeadbeef);
16657 old_focus = SetFocus(GetDesktopWindow());
16658 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16659 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16660 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16661 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
16662 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16663 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16664 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16665
16666 SetLastError(0xdeadbeef);
16667 old_focus = SetFocus(wnd_event.hwnd);
16668 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16669 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16670 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16671 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
16672 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16673 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16674 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16675
16676 SetLastError(0xdeadbeef);
16677 old_active = SetActiveWindow((HWND)0xdeadbeef);
16678 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16679 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16680 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16681 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
16682 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16683 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16684 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16685
16686 SetLastError(0xdeadbeef);
16687 old_active = SetActiveWindow(GetDesktopWindow());
16688 todo_wine
16689 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16690 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16691 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
16692 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
16693 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16694 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16695
16696 SetLastError(0xdeadbeef);
16697 old_active = SetActiveWindow(wnd_event.hwnd);
16698 todo_wine
16699 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16700 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16701 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
16702 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16703 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16704 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16705
16706 SetLastError(0xdeadbeef);
16707 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
16708 ok(ret, "AttachThreadInput error %d\n", GetLastError());
16709
16710 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16711 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16712
16713 flush_events();
16714 flush_sequence();
16715
16716 old_focus = SetFocus(wnd_event.hwnd);
16717 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16718 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
16719 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16720 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16721
16722 old_focus = SetFocus(parent);
16723 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16724 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16725 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16726 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16727
16728 flush_events();
16729 flush_sequence();
16730
16731 old_active = SetActiveWindow(wnd_event.hwnd);
16732 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16733 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
16734 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16735 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16736
16737 SetLastError(0xdeadbeef);
16738 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
16739 ok(ret, "AttachThreadInput error %d\n", GetLastError());
16740
16741 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16742 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16743
16744 old_parent = SetParent(child, GetDesktopWindow());
16745 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
16746
16747 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16748 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16749
16750 old_focus = SetFocus(parent);
16751 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16752 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16753 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16754 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16755
16756 flush_events();
16757 flush_sequence();
16758
16759 SetLastError(0xdeadbeef);
16760 old_focus = SetFocus(child);
16761 todo_wine
16762 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
16763 broken(GetLastError() == 0) /* XP */ ||
16764 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
16765 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16766 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
16767 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16768 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16769 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16770
16771 SetLastError(0xdeadbeef);
16772 old_active = SetActiveWindow(child);
16773 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16774 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16775 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
16776 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
16777 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16778 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16779
16780 log_all_parent_messages--;
16781
16782 DestroyWindow(child);
16783 DestroyWindow(parent);
16784
16785 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
16786 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
16787 ret = WaitForSingleObject(hthread, INFINITE);
16788 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16789 CloseHandle(hthread);
16790 }
16791
16792 static const struct message WmSetLayeredStyle[] = {
16793 { WM_STYLECHANGING, sent },
16794 { WM_STYLECHANGED, sent },
16795 { WM_GETTEXT, sent|defwinproc|optional },
16796 { 0 }
16797 };
16798
16799 static const struct message WmSetLayeredStyle2[] = {
16800 { WM_STYLECHANGING, sent },
16801 { WM_STYLECHANGED, sent },
16802 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16803 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
16804 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16805 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
16806 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
16807 { 0 }
16808 };
16809
16810 struct layered_window_info
16811 {
16812 HWND hwnd;
16813 HDC hdc;
16814 SIZE size;
16815 HANDLE event;
16816 BOOL ret;
16817 };
16818
16819 static DWORD CALLBACK update_layered_proc( void *param )
16820 {
16821 struct layered_window_info *info = param;
16822 POINT src = { 0, 0 };
16823
16824 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
16825 info->hdc, &src, 0, NULL, ULW_OPAQUE );
16826 ok( info->ret, "failed\n");
16827 SetEvent( info->event );
16828 return 0;
16829 }
16830
16831 static void test_layered_window(void)
16832 {
16833 HWND hwnd;
16834 HDC hdc;
16835 HBITMAP bmp;
16836 BOOL ret;
16837 SIZE size;
16838 POINT pos, src;
16839 RECT rect, client;
16840 HANDLE thread;
16841 DWORD tid;
16842 struct layered_window_info info;
16843
16844 if (!pUpdateLayeredWindow)
16845 {
16846 win_skip( "UpdateLayeredWindow not supported\n" );
16847 return;
16848 }
16849
16850 hdc = CreateCompatibleDC( 0 );
16851 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
16852 SelectObject( hdc, bmp );
16853
16854 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
16855 100, 100, 300, 300, 0, 0, 0, NULL);
16856 ok( hwnd != 0, "failed to create window\n" );
16857 ShowWindow( hwnd, SW_SHOWNORMAL );
16858 UpdateWindow( hwnd );
16859 flush_events();
16860 flush_sequence();
16861
16862 GetWindowRect( hwnd, &rect );
16863 GetClientRect( hwnd, &client );
16864 ok( client.right < rect.right - rect.left, "wrong client area\n" );
16865 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
16866
16867 src.x = src.y = 0;
16868 pos.x = pos.y = 300;
16869 size.cx = size.cy = 250;
16870 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16871 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16872 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16873 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16874 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16875
16876 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16877 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16878 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16879 GetWindowRect( hwnd, &rect );
16880 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
16881 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16882 GetClientRect( hwnd, &rect );
16883 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
16884 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16885
16886 size.cx = 150;
16887 pos.y = 200;
16888 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16889 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16890 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16891 GetWindowRect( hwnd, &rect );
16892 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
16893 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16894 GetClientRect( hwnd, &rect );
16895 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
16896 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16897
16898 SetWindowLongA( hwnd, GWL_STYLE,
16899 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
16900 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
16901
16902 size.cx = 200;
16903 pos.x = 200;
16904 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16905 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16906 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16907 GetWindowRect( hwnd, &rect );
16908 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16909 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16910 GetClientRect( hwnd, &rect );
16911 ok( (rect.right == 200 && rect.bottom == 250) ||
16912 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16913 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16914
16915 size.cx = 0;
16916 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16917 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16918 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
16919 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
16920 size.cx = 1;
16921 size.cy = -1;
16922 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16923 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16924 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16925
16926 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
16927 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16928 GetWindowRect( hwnd, &rect );
16929 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16930 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16931 GetClientRect( hwnd, &rect );
16932 ok( (rect.right == 200 && rect.bottom == 250) ||
16933 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16934 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16935
16936 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16937 info.hwnd = hwnd;
16938 info.hdc = hdc;
16939 info.size.cx = 250;
16940 info.size.cy = 300;
16941 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
16942 info.ret = FALSE;
16943 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
16944 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
16945 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
16946 WaitForSingleObject( thread, 1000 );
16947 CloseHandle( thread );
16948 GetWindowRect( hwnd, &rect );
16949 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
16950 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16951 GetClientRect( hwnd, &rect );
16952 ok( (rect.right == 250 && rect.bottom == 300) ||
16953 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
16954 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16955
16956 DestroyWindow( hwnd );
16957 DeleteDC( hdc );
16958 DeleteObject( bmp );
16959 }
16960
16961 static HMENU hpopupmenu;
16962
16963 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16964 {
16965 if (ignore_message( message )) return 0;
16966
16967 switch (message) {
16968 case WM_ENTERIDLE:
16969 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
16970 EndMenu();
16971 break;
16972 case WM_INITMENU:
16973 case WM_INITMENUPOPUP:
16974 case WM_UNINITMENUPOPUP:
16975 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
16976 break;
16977 case WM_CAPTURECHANGED:
16978 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
16979 break;
16980 }
16981
16982 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16983 }
16984
16985 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16986 {
16987 if (ignore_message( message )) return 0;
16988
16989 switch (message) {
16990 case WM_ENTERMENULOOP:
16991 ok(EndMenu() == TRUE, "EndMenu() failed\n");
16992 break;
16993 }
16994
16995 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16996 }
16997
16998 static void test_TrackPopupMenu(void)
16999 {
17000 MSG msg;
17001 HWND hwnd;
17002 BOOL ret;
17003
17004 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17005 0, 0, 1, 1, 0,
17006 NULL, NULL, 0);
17007 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17008
17009 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17010
17011 hpopupmenu = CreatePopupMenu();
17012 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17013
17014 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
17015 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
17016
17017 flush_events();
17018 flush_sequence();
17019 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17020 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
17021 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17022
17023 /* Test popup closing with an ESC-press */
17024 flush_events();
17025 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
17026 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17027 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17028 PostQuitMessage(0);
17029 flush_sequence();
17030 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
17031 {
17032 TranslateMessage(&msg);
17033 DispatchMessageA(&msg);
17034 }
17035 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
17036
17037 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
17038
17039 flush_events();
17040 flush_sequence();
17041 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17042 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
17043 ok(ret == TRUE, "TrackPopupMenu failed\n");
17044
17045 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17046
17047 SetCapture(hwnd);
17048
17049 flush_events();
17050 flush_sequence();
17051 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17052 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
17053 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
17054
17055 DestroyMenu(hpopupmenu);
17056 DestroyWindow(hwnd);
17057 }
17058
17059 static void test_TrackPopupMenuEmpty(void)
17060 {
17061 HWND hwnd;
17062 BOOL ret;
17063
17064 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17065 0, 0, 1, 1, 0,
17066 NULL, NULL, 0);
17067 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17068
17069 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17070
17071 hpopupmenu = CreatePopupMenu();
17072 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17073
17074 flush_events();
17075 flush_sequence();
17076 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17077 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
17078 ok(ret == 0, "TrackPopupMenu succeeded\n");
17079
17080 DestroyMenu(hpopupmenu);
17081 DestroyWindow(hwnd);
17082 }
17083
17084 static const struct message send_message_1[] = {
17085 { WM_USER+2, sent|wparam|lparam, 0, 0 },
17086 { WM_USER, sent|wparam|lparam, 0, 0 },
17087 { 0 }
17088 };
17089 static const struct message send_message_2[] = {
17090 { WM_USER+4, sent|wparam|lparam, 0, 0 },
17091 { 0 }
17092 };
17093 static const struct message send_message_3[] = {
17094 { WM_USER+3, sent|wparam|lparam, 0, 0 },
17095 { WM_USER+1, sent|wparam|lparam, 0, 0 },
17096 { 0 }
17097 };
17098
17099 static DWORD WINAPI SendMessage_thread_1(void *param)
17100 {
17101 struct wnd_event *wnd_event = param;
17102
17103 trace("thread: starting\n");
17104 WaitForSingleObject(wnd_event->start_event, INFINITE);
17105
17106 trace("thread: call PostMessage\n");
17107 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17108
17109 trace("thread: call PostMessage\n");
17110 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17111
17112 trace("thread: call SendMessage\n");
17113 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17114
17115 trace("thread: call SendMessage\n");
17116 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17117
17118 return 0;
17119 }
17120
17121 static DWORD WINAPI SendMessage_thread_2(void *param)
17122 {
17123 struct wnd_event *wnd_event = param;
17124
17125 trace("thread: starting\n");
17126 WaitForSingleObject(wnd_event->start_event, INFINITE);
17127
17128 trace("thread: call PostMessage\n");
17129 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17130
17131 trace("thread: call PostMessage\n");
17132 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17133
17134 /* this leads to sending an internal message under Wine */
17135 trace("thread: call SetParent\n");
17136 SetParent(wnd_event->hwnd, wnd_event->hwnd);
17137
17138 trace("thread: call SendMessage\n");
17139 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17140
17141 trace("thread: call SendMessage\n");
17142 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17143
17144 return 0;
17145 }
17146
17147 static void test_SendMessage_other_thread(int thread_n)
17148 {
17149 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
17150 HANDLE hthread;
17151 struct wnd_event wnd_event;
17152 DWORD tid, ret;
17153 MSG msg;
17154
17155 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
17156
17157 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
17158 100, 100, 200, 200, 0, 0, 0, NULL);
17159 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
17160
17161 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
17162 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
17163 CloseHandle(hthread);
17164
17165 flush_events();
17166 flush_sequence();
17167
17168 ret = GetQueueStatus(QS_SENDMESSAGE);
17169 ok(ret == 0, "wrong status %08x\n", ret);
17170
17171 SetEvent(wnd_event.start_event);
17172
17173 /* wait for other thread's SendMessage */
17174 for (;;)
17175 {
17176 ret = GetQueueStatus(QS_SENDMESSAGE);
17177 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17178 Sleep(50);
17179 }
17180
17181 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17182 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17183
17184 trace("main: call GetMessage\n");
17185 GetMessageA(&msg, 0, 0, 0);
17186 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17187 DispatchMessageA(&msg);
17188 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17189
17190 /* intentionally yield */
17191 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17192
17193 trace("main: call SendMessage\n");
17194 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17195 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17196
17197 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17198 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17199
17200 trace("main: call PeekMessage\n");
17201 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17202 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17203 DispatchMessageA(&msg);
17204 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17205
17206 /* intentionally yield */
17207 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17208
17209 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17210 /* FIXME: remove once Wine is fixed */
17211 todo_wine_if (thread_n == 2)
17212 ok(ret == 0, "wrong status %08x\n", ret);
17213
17214 trace("main: call PeekMessage\n");
17215 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17216 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17217
17218 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17219 ok(ret == 0, "wrong status %08x\n", ret);
17220
17221 trace("main: call DestroyWindow\n");
17222 DestroyWindow(msg.hwnd);
17223
17224 flush_events();
17225 flush_sequence();
17226 }
17227
17228 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17229 {
17230 DWORD flags = InSendMessageEx( NULL );
17231 BOOL ret;
17232
17233 switch (msg)
17234 {
17235 case WM_USER:
17236 ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17237 ok( InSendMessage(), "InSendMessage returned false\n" );
17238 ret = ReplyMessage( msg );
17239 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17240 flags = InSendMessageEx( NULL );
17241 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17242 ok( InSendMessage(), "InSendMessage returned false\n" );
17243 break;
17244 case WM_USER + 1:
17245 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17246 ok( InSendMessage(), "InSendMessage returned false\n" );
17247 ret = ReplyMessage( msg );
17248 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17249 flags = InSendMessageEx( NULL );
17250 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17251 ok( InSendMessage(), "InSendMessage returned false\n" );
17252 break;
17253 case WM_USER + 2:
17254 ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17255 ok( InSendMessage(), "InSendMessage returned false\n" );
17256 ret = ReplyMessage( msg );
17257 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17258 flags = InSendMessageEx( NULL );
17259 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
17260 ok( InSendMessage(), "InSendMessage returned false\n" );
17261 break;
17262 case WM_USER + 3:
17263 ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
17264 ok( !InSendMessage(), "InSendMessage returned true\n" );
17265 ret = ReplyMessage( msg );
17266 ok( !ret, "ReplyMessage succeeded\n" );
17267 break;
17268 }
17269
17270 return DefWindowProcA( hwnd, msg, wp, lp );
17271 }
17272
17273 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
17274 {
17275 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
17276 ok( result == WM_USER + 2, "wrong result %lx\n", result );
17277 }
17278
17279 static DWORD WINAPI send_message_thread( void *arg )
17280 {
17281 HWND win = arg;
17282
17283 SendMessageA( win, WM_USER, 0, 0 );
17284 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
17285 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
17286 PostMessageA( win, WM_USER + 3, 0, 0 );
17287 PostMessageA( win, WM_QUIT, 0, 0 );
17288 return 0;
17289 }
17290
17291 static void test_InSendMessage(void)
17292 {
17293 WNDCLASSA cls;
17294 HWND win;
17295 MSG msg;
17296 HANDLE thread;
17297 DWORD tid;
17298
17299 memset(&cls, 0, sizeof(cls));
17300 cls.lpfnWndProc = insendmessage_wnd_proc;
17301 cls.hInstance = GetModuleHandleA(NULL);
17302 cls.lpszClassName = "InSendMessage_test";
17303 RegisterClassA(&cls);
17304
17305 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
17306 ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
17307
17308 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
17309 ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
17310
17311 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
17312
17313 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
17314 CloseHandle( thread );
17315
17316 DestroyWindow( win );
17317 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
17318 }
17319
17320 static const struct message DoubleSetCaptureSeq[] =
17321 {
17322 { WM_CAPTURECHANGED, sent },
17323 { 0 }
17324 };
17325
17326 static void test_DoubleSetCapture(void)
17327 {
17328 HWND hwnd;
17329
17330 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
17331 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17332 100, 100, 200, 200, 0, 0, 0, NULL);
17333 ok (hwnd != 0, "Failed to create overlapped window\n");
17334
17335 ShowWindow( hwnd, SW_SHOW );
17336 UpdateWindow( hwnd );
17337 flush_events();
17338 flush_sequence();
17339
17340 SetCapture( hwnd );
17341 SetCapture( hwnd );
17342 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
17343
17344 DestroyWindow(hwnd);
17345 }
17346
17347 static void init_funcs(void)
17348 {
17349 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
17350
17351 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
17352 X(ActivateActCtx);
17353 X(CreateActCtxW);
17354 X(DeactivateActCtx);
17355 X(GetCurrentActCtx);
17356 X(QueryActCtxW);
17357 X(ReleaseActCtx);
17358 #undef X
17359 }
17360
17361 #ifndef __REACTOS__
17362 START_TEST(msg)
17363 {
17364 char **test_argv;
17365 BOOL ret;
17366 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17367 HMODULE hModuleImm32;
17368 BOOL (WINAPI *pImmDisableIME)(DWORD);
17369 int argc;
17370
17371 init_funcs();
17372
17373 argc = winetest_get_mainargs( &test_argv );
17374 if (argc >= 3)
17375 {
17376 unsigned int arg;
17377 /* Child process. */
17378 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17379 do_wait_idle_child( arg );
17380 return;
17381 }
17382
17383 InitializeCriticalSection( &sequence_cs );
17384 init_procs();
17385
17386 hModuleImm32 = LoadLibraryA("imm32.dll");
17387 if (hModuleImm32) {
17388 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17389 if (pImmDisableIME)
17390 pImmDisableIME(0);
17391 }
17392 pImmDisableIME = NULL;
17393 FreeLibrary(hModuleImm32);
17394
17395 if (!RegisterWindowClasses()) assert(0);
17396
17397 if (pSetWinEventHook)
17398 {
17399 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17400 GetModuleHandleA(0), win_event_proc,
17401 0, GetCurrentThreadId(),
17402 WINEVENT_INCONTEXT);
17403 if (pIsWinEventHookInstalled && hEvent_hook)
17404 {
17405 UINT event;
17406 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17407 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17408 }
17409 }
17410 if (!hEvent_hook) win_skip( "no win event hook support\n" );
17411
17412 cbt_hook_thread_id = GetCurrentThreadId();
17413 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17414 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17415
17416 test_winevents();
17417
17418 /* Fix message sequences before removing 4 lines below */
17419 if (pUnhookWinEvent && hEvent_hook)
17420 {
17421 ret = pUnhookWinEvent(hEvent_hook);
17422 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17423 pUnhookWinEvent = 0;
17424 }
17425 hEvent_hook = 0;
17426
17427 test_SendMessage_other_thread(1);
17428 test_SendMessage_other_thread(2);
17429 test_InSendMessage();
17430 test_SetFocus();
17431 test_SetParent();
17432 test_PostMessage();
17433 test_broadcast();
17434 test_ShowWindow();
17435 test_PeekMessage();
17436 test_PeekMessage2();
17437 test_PeekMessage3();
17438 test_WaitForInputIdle( test_argv[0] );
17439 test_scrollwindowex();
17440 test_messages();
17441 test_setwindowpos();
17442 test_showwindow();
17443 invisible_parent_tests();
17444 test_mdi_messages();
17445 test_button_messages();
17446 test_autoradio_BM_CLICK();
17447 test_autoradio_kbd_move();
17448 test_static_messages();
17449 test_listbox_messages();
17450 test_combobox_messages();
17451 test_wmime_keydown_message();
17452 test_paint_messages();
17453 test_interthread_messages();
17454 test_message_conversion();
17455 test_accelerators();
17456 test_timers();
17457 test_timers_no_wnd();
17458 test_timers_exceptions();
17459 if (hCBT_hook)
17460 {
17461 test_set_hook();
17462 test_recursive_hook();
17463 }
17464 test_DestroyWindow();
17465 test_DispatchMessage();
17466 test_SendMessageTimeout();
17467 test_edit_messages();
17468 test_quit_message();
17469 test_notify_message();
17470 test_SetActiveWindow();
17471
17472 if (!pTrackMouseEvent)
17473 win_skip("TrackMouseEvent is not available\n");
17474 else
17475 test_TrackMouseEvent();
17476
17477 test_SetWindowRgn();
17478 test_sys_menu();
17479 test_dialog_messages();
17480 test_EndDialog();
17481 test_nullCallback();
17482 test_dbcs_wm_char();
17483 test_unicode_wm_char();
17484 test_menu_messages();
17485 test_paintingloop();
17486 test_defwinproc();
17487 test_clipboard_viewers();
17488 test_keyflags();
17489 test_hotkey();
17490 test_layered_window();
17491 test_TrackPopupMenu();
17492 test_TrackPopupMenuEmpty();
17493 test_DoubleSetCapture();
17494 /* keep it the last test, under Windows it tends to break the tests
17495 * which rely on active/foreground windows being correct.
17496 */
17497 test_SetForegroundWindow();
17498
17499 UnhookWindowsHookEx(hCBT_hook);
17500 if (pUnhookWinEvent && hEvent_hook)
17501 {
17502 ret = pUnhookWinEvent(hEvent_hook);
17503 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17504 SetLastError(0xdeadbeef);
17505 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17506 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17507 GetLastError() == 0xdeadbeef, /* Win9x */
17508 "unexpected error %d\n", GetLastError());
17509 }
17510 DeleteCriticalSection( &sequence_cs );
17511 }
17512 #endif /* __REACTOS__ */
17513
17514 static void init_tests()
17515 {
17516 HMODULE hModuleImm32;
17517 BOOL (WINAPI *pImmDisableIME)(DWORD);
17518
17519 init_funcs();
17520
17521 InitializeCriticalSection( &sequence_cs );
17522 init_procs();
17523
17524 hModuleImm32 = LoadLibraryA("imm32.dll");
17525 if (hModuleImm32) {
17526 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17527 if (pImmDisableIME)
17528 pImmDisableIME(0);
17529 }
17530 pImmDisableIME = NULL;
17531 FreeLibrary(hModuleImm32);
17532
17533 if (!RegisterWindowClasses()) assert(0);
17534
17535 cbt_hook_thread_id = GetCurrentThreadId();
17536 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17537 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17538 }
17539
17540 static void cleanup_tests()
17541 {
17542 BOOL ret;
17543 UnhookWindowsHookEx(hCBT_hook);
17544 if (pUnhookWinEvent && hEvent_hook)
17545 {
17546 ret = pUnhookWinEvent(hEvent_hook);
17547 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17548 SetLastError(0xdeadbeef);
17549 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17550 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17551 GetLastError() == 0xdeadbeef, /* Win9x */
17552 "unexpected error %d\n", GetLastError());
17553 }
17554 DeleteCriticalSection( &sequence_cs );
17555
17556 }
17557
17558 START_TEST(msg_queue)
17559 {
17560 int argc;
17561 char **test_argv;
17562 argc = winetest_get_mainargs( &test_argv );
17563 if (argc >= 3)
17564 {
17565 unsigned int arg;
17566 /* Child process. */
17567 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17568 do_wait_idle_child( arg );
17569 return;
17570 }
17571
17572 init_tests();
17573 test_SendMessage_other_thread(1);
17574 test_SendMessage_other_thread(2);
17575 test_InSendMessage();
17576 test_PostMessage();
17577 test_broadcast();
17578 test_PeekMessage();
17579 test_PeekMessage2();
17580 test_PeekMessage3();
17581 test_interthread_messages();
17582 test_DispatchMessage();
17583 test_SendMessageTimeout();
17584 test_quit_message();
17585 test_notify_message();
17586 test_WaitForInputIdle( test_argv[0] );
17587 test_DestroyWindow();
17588 cleanup_tests();
17589 }
17590
17591 START_TEST(msg_messages)
17592 {
17593 init_tests();
17594 test_message_conversion();
17595 test_messages();
17596 test_wmime_keydown_message();
17597 test_nullCallback();
17598 test_dbcs_wm_char();
17599 test_unicode_wm_char();
17600 test_defwinproc();
17601 cleanup_tests();
17602 }
17603
17604 START_TEST(msg_focus)
17605 {
17606 init_tests();
17607
17608 test_SetFocus();
17609
17610 /* HACK: For some reason the tests fail on Windows if run consecutively.
17611 * Putting these in between helps, and is essentially what happens in the
17612 * "normal" msg test. */
17613 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17614 flush_events();
17615
17616 test_SetActiveWindow();
17617
17618 /* HACK */
17619 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17620 flush_events();
17621
17622 test_DoubleSetCapture();
17623
17624 /* keep it the last test, under Windows it tends to break the tests
17625 * which rely on active/foreground windows being correct.
17626 */
17627 test_SetForegroundWindow();
17628 cleanup_tests();
17629 }
17630
17631 START_TEST(msg_winpos)
17632 {
17633 init_tests();
17634 test_SetParent();
17635 test_ShowWindow();
17636 test_setwindowpos();
17637 test_showwindow();
17638 test_SetWindowRgn();
17639 invisible_parent_tests();
17640 cleanup_tests();
17641 }
17642
17643 START_TEST(msg_paint)
17644 {
17645 init_tests();
17646 test_scrollwindowex();
17647 test_paint_messages();
17648 #ifdef __REACTOS__
17649 if (!winetest_interactive &&
17650 !strcmp(winetest_platform, "windows"))
17651 {
17652 skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
17653 }
17654 else
17655 #endif
17656 test_paintingloop();
17657 cleanup_tests();
17658 }
17659
17660 START_TEST(msg_input)
17661 {
17662 init_tests();
17663 test_accelerators();
17664 if (!pTrackMouseEvent)
17665 win_skip("TrackMouseEvent is not available\n");
17666 else
17667 test_TrackMouseEvent();
17668
17669 test_keyflags();
17670 test_hotkey();
17671 cleanup_tests();
17672 }
17673
17674 START_TEST(msg_timer)
17675 {
17676 init_tests();
17677 test_timers();
17678 test_timers_no_wnd();
17679 test_timers_exceptions();
17680 cleanup_tests();
17681 }
17682
17683 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
17684
17685 START_TEST(msg_hook)
17686 {
17687 // HMODULE user32 = GetModuleHandleA("user32.dll");
17688 // IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
17689 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17690
17691 init_tests();
17692
17693 if (pSetWinEventHook)
17694 {
17695 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17696 GetModuleHandleA(0), win_event_proc,
17697 0, GetCurrentThreadId(),
17698 WINEVENT_INCONTEXT);
17699 if (pIsWinEventHookInstalled && hEvent_hook)
17700 {
17701 UINT event;
17702 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17703 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17704 }
17705 }
17706 if (!hEvent_hook) win_skip( "no win event hook support\n" );
17707
17708 test_winevents();
17709
17710 /* Fix message sequences before removing 4 lines below */
17711 if (pUnhookWinEvent && hEvent_hook)
17712 {
17713 BOOL ret;
17714 ret = pUnhookWinEvent(hEvent_hook);
17715 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17716 pUnhookWinEvent = 0;
17717 }
17718 hEvent_hook = 0;
17719 if (hCBT_hook)
17720 {
17721 test_set_hook();
17722 test_recursive_hook();
17723 }
17724 cleanup_tests();
17725 }
17726
17727 START_TEST(msg_menu)
17728 {
17729 init_tests();
17730 test_sys_menu();
17731 test_menu_messages();
17732 test_TrackPopupMenu();
17733 test_TrackPopupMenuEmpty();
17734 cleanup_tests();
17735 }
17736
17737 START_TEST(msg_mdi)
17738 {
17739 init_tests();
17740 test_mdi_messages();
17741 cleanup_tests();
17742 }
17743
17744 START_TEST(msg_controls)
17745 {
17746 init_tests();
17747 test_button_messages();
17748 test_autoradio_BM_CLICK();
17749 test_autoradio_kbd_move();
17750 test_static_messages();
17751 test_listbox_messages();
17752 test_combobox_messages();
17753 test_edit_messages();
17754 cleanup_tests();
17755 }
17756
17757 START_TEST(msg_layered_window)
17758 {
17759 init_tests();
17760 test_layered_window();
17761 cleanup_tests();
17762 }
17763
17764 START_TEST(msg_dialog)
17765 {
17766 init_tests();
17767 test_dialog_messages();
17768 test_EndDialog();
17769 cleanup_tests();
17770 }
17771
17772 START_TEST(msg_clipboard)
17773 {
17774 init_tests();
17775 test_clipboard_viewers();
17776 cleanup_tests();
17777 }