[USER32_WINETEST] Sync with Wine Staging 2.9 except win.c. CORE-13362
[reactos.git] / rostests / winetests / user32 / msg.c
1 /*
2 * Unit tests for window message handling
3 *
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004,2005,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 //#define _WIN32_WINNT 0x0600 /* For WM_CHANGEUISTATE,QS_RAWINPUT,WM_DWMxxxx */
24 //#define WINVER 0x0600 /* for WM_GETTITLEBARINFOEX */
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35 #include "dbt.h"
36
37 #include "wine/test.h"
38
39 #define MDI_FIRST_CHILD_ID 2004
40
41 /* undocumented SWP flags - from SDK 3.1 */
42 #define SWP_NOCLIENTSIZE 0x0800
43 #define SWP_NOCLIENTMOVE 0x1000
44 #define SWP_STATECHANGED 0x8000
45
46 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
47
48 #ifndef WM_KEYF1
49 #define WM_KEYF1 0x004d
50 #endif
51
52 #ifndef WM_SYSTIMER
53 #define WM_SYSTIMER 0x0118
54 #endif
55
56 #define WND_PARENT_ID 1
57 #define WND_POPUP_ID 2
58 #define WND_CHILD_ID 3
59
60 #ifndef WM_LBTRACKPOINT
61 #define WM_LBTRACKPOINT 0x0131
62 #endif
63
64 #ifdef __i386__
65 #define ARCH "x86"
66 #elif defined __x86_64__
67 #define ARCH "amd64"
68 #elif defined __arm__
69 #define ARCH "arm"
70 #elif defined __aarch64__
71 #define ARCH "arm64"
72 #else
73 #define ARCH "none"
74 #endif
75
76 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
77 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
78 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
79 static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
80 static BOOL (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
81 static void (WINAPI *pReleaseActCtx)(HANDLE);
82
83 /* encoded DRAWITEMSTRUCT into an LPARAM */
84 typedef struct
85 {
86 union
87 {
88 struct
89 {
90 UINT type : 4; /* ODT_* flags */
91 UINT ctl_id : 4; /* Control ID */
92 UINT item_id : 4; /* Menu item ID */
93 UINT action : 4; /* ODA_* flags */
94 UINT state : 16; /* ODS_* flags */
95 } item;
96 LPARAM lp;
97 } u;
98 } DRAW_ITEM_STRUCT;
99
100 /* encoded MEASUREITEMSTRUCT into a WPARAM */
101 typedef struct
102 {
103 union
104 {
105 struct
106 {
107 UINT CtlType : 4;
108 UINT CtlID : 4;
109 UINT itemID : 4;
110 UINT wParam : 20;
111 } item;
112 WPARAM wp;
113 } u;
114 } MEASURE_ITEM_STRUCT;
115
116 static BOOL test_DestroyWindow_flag;
117 static HWINEVENTHOOK hEvent_hook;
118 static HHOOK hKBD_hook;
119 static HHOOK hCBT_hook;
120 static DWORD cbt_hook_thread_id;
121
122 static const WCHAR testWindowClassW[] =
123 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
124
125 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
126
127 /*
128 FIXME: add tests for these
129 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
130 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
131 WS_THICKFRAME: thick border
132 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
133 WS_BORDER (default for overlapped windows): single black border
134 none (default for child (and popup?) windows): no border
135 */
136
137 typedef enum {
138 sent=0x1,
139 posted=0x2,
140 parent=0x4,
141 wparam=0x8,
142 lparam=0x10,
143 defwinproc=0x20,
144 beginpaint=0x40,
145 optional=0x80,
146 hook=0x100,
147 winevent_hook=0x200,
148 kbd_hook=0x400
149 } msg_flags_t;
150
151 struct message {
152 UINT message; /* the WM_* code */
153 msg_flags_t flags; /* message props */
154 WPARAM wParam; /* expected value of wParam */
155 LPARAM lParam; /* expected value of lParam */
156 WPARAM wp_mask; /* mask for wParam checks */
157 LPARAM lp_mask; /* mask for lParam checks */
158 };
159
160 struct recvd_message {
161 UINT message; /* the WM_* code */
162 msg_flags_t flags; /* message props */
163 HWND hwnd; /* window that received the message */
164 WPARAM wParam; /* expected value of wParam */
165 LPARAM lParam; /* expected value of lParam */
166 int line; /* source line where logged */
167 const char *descr; /* description for trace output */
168 char output[512]; /* trace output */
169 };
170
171 /* Empty message sequence */
172 static const struct message WmEmptySeq[] =
173 {
174 { 0 }
175 };
176 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
177 static const struct message WmCreateOverlappedSeq[] = {
178 { HCBT_CREATEWND, hook },
179 { WM_GETMINMAXINFO, sent },
180 { WM_NCCREATE, sent },
181 { WM_NCCALCSIZE, sent|wparam, 0 },
182 { 0x0093, sent|defwinproc|optional },
183 { 0x0094, sent|defwinproc|optional },
184 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
185 { WM_CREATE, sent },
186 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
187 { 0 }
188 };
189 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
190 * for a not visible overlapped window.
191 */
192 static const struct message WmSWP_ShowOverlappedSeq[] = {
193 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
194 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
195 { WM_NCPAINT, sent|wparam|optional, 1 },
196 { WM_GETTEXT, sent|defwinproc|optional },
197 { WM_ERASEBKGND, sent|optional },
198 { HCBT_ACTIVATE, hook },
199 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
200 { WM_NOTIFYFORMAT, sent|optional },
201 { WM_QUERYUISTATE, sent|optional },
202 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
203 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
204 { WM_ACTIVATEAPP, sent|wparam, 1 },
205 { WM_NCACTIVATE, sent },
206 { WM_GETTEXT, sent|defwinproc|optional },
207 { WM_ACTIVATE, sent|wparam, 1 },
208 { HCBT_SETFOCUS, hook },
209 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
210 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
211 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
212 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
213 { WM_GETTEXT, sent|optional },
214 { WM_NCPAINT, sent|wparam|optional, 1 },
215 { WM_GETTEXT, sent|defwinproc|optional },
216 { WM_ERASEBKGND, sent|optional },
217 /* Win9x adds SWP_NOZORDER below */
218 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
219 { WM_GETTEXT, sent|optional },
220 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
221 { WM_NCPAINT, sent|wparam|optional, 1 },
222 { WM_ERASEBKGND, sent|optional },
223 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
224 { WM_SYNCPAINT, sent|optional },
225 { WM_GETTITLEBARINFOEX, sent|optional },
226 { WM_PAINT, sent|optional },
227 { WM_NCPAINT, sent|beginpaint|optional },
228 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
229 { WM_ERASEBKGND, sent|beginpaint|optional },
230 { 0 }
231 };
232 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
233 * for a visible overlapped window.
234 */
235 static const struct message WmSWP_HideOverlappedSeq[] = {
236 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
237 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
238 { HCBT_ACTIVATE, hook|optional },
239 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
240 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
241 { WM_NCACTIVATE, sent|optional },
242 { WM_ACTIVATE, sent|optional },
243 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
244 { 0 }
245 };
246
247 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
248 * for a visible overlapped window.
249 */
250 static const struct message WmSWP_ResizeSeq[] = {
251 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
252 { WM_GETMINMAXINFO, sent|defwinproc },
253 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
254 { WM_NCPAINT, sent|optional },
255 { WM_GETTEXT, sent|defwinproc|optional },
256 { WM_ERASEBKGND, sent|optional },
257 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
258 { WM_SIZE, sent|defwinproc|optional },
259 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
260 { WM_NCPAINT, sent|optional },
261 { WM_GETTEXT, sent|defwinproc|optional },
262 { WM_ERASEBKGND, sent|optional },
263 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
264 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
265 { 0 }
266 };
267
268 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
269 * for a visible popup window.
270 */
271 static const struct message WmSWP_ResizePopupSeq[] = {
272 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
273 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
274 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
275 { WM_NCPAINT, sent|optional },
276 { WM_GETTEXT, sent|defwinproc|optional },
277 { WM_ERASEBKGND, sent|optional },
278 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
279 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
280 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
281 { WM_NCPAINT, sent|optional },
282 { WM_GETTEXT, sent|defwinproc|optional },
283 { WM_ERASEBKGND, sent|optional },
284 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
285 { 0 }
286 };
287
288 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
289 * for a visible overlapped window.
290 */
291 static const struct message WmSWP_MoveSeq[] = {
292 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
293 { WM_NCPAINT, sent|optional },
294 { WM_GETTEXT, sent|defwinproc|optional },
295 { WM_ERASEBKGND, sent|optional },
296 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
297 { WM_MOVE, sent|defwinproc|wparam, 0 },
298 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
299 { 0 }
300 };
301 /* Resize with SetWindowPos(SWP_NOZORDER)
302 * for a visible overlapped window
303 * SWP_NOZORDER is stripped by the logging code
304 */
305 static const struct message WmSWP_ResizeNoZOrder[] = {
306 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
307 { WM_GETMINMAXINFO, sent|defwinproc },
308 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
309 { WM_NCPAINT, sent|optional },
310 { WM_GETTEXT, sent|defwinproc|optional },
311 { WM_ERASEBKGND, sent|optional },
312 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
313 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
314 { WM_MOVE, sent|defwinproc|optional },
315 { WM_SIZE, sent|defwinproc|optional },
316 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
317 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
318 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
319 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
320 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
321 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
322 { 0 }
323 };
324
325 /* Switch visible mdi children */
326 static const struct message WmSwitchChild[] = {
327 /* Switch MDI child */
328 { WM_MDIACTIVATE, sent },/* in the MDI client */
329 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
330 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
331 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
332 /* Deactivate 2nd MDI child */
333 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
334 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
335 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
336 /* Preparing for maximize and maximize the 1st MDI child */
337 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
338 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
339 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
340 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
341 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
342 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
343 /* Lock redraw 2nd MDI child */
344 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
345 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
346 /* Restore 2nd MDI child */
347 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
348 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
349 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
350 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
351 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
352 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
353 /* Redraw 2nd MDI child */
354 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
355 /* Redraw MDI frame */
356 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
357 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
358 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
359 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
360 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
361 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
362 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
363 { HCBT_SETFOCUS, hook },
364 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
365 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
366 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
367 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
368 { WM_SETFOCUS, sent },/* in the MDI client */
369 { HCBT_SETFOCUS, hook },
370 { WM_KILLFOCUS, sent },/* in the MDI client */
371 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
372 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
373 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
374 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
375 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
376 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
377 { 0 }
378 };
379
380 /* Switch visible not maximized mdi children */
381 static const struct message WmSwitchNotMaximizedChild[] = {
382 /* Switch not maximized MDI child */
383 { WM_MDIACTIVATE, sent },/* in the MDI client */
384 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
385 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
386 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
387 /* Deactivate 1st MDI child */
388 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
389 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
390 /* Activate 2nd MDI child */
391 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
392 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
393 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
394 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
395 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
396 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
397 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
398 { HCBT_SETFOCUS, hook },
399 { WM_KILLFOCUS, sent }, /* in the MDI client */
400 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
401 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
402 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
403 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
404 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
405 { 0 }
406 };
407
408
409 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
410 SWP_NOZORDER|SWP_FRAMECHANGED)
411 * for a visible overlapped window with WS_CLIPCHILDREN style set.
412 */
413 static const struct message WmSWP_FrameChanged_clip[] = {
414 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
415 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
416 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
417 { WM_GETTEXT, sent|parent|defwinproc|optional },
418 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
419 { WM_NCPAINT, sent }, /* wparam != 1 */
420 { WM_ERASEBKGND, sent },
421 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
422 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
423 { WM_PAINT, sent },
424 { 0 }
425 };
426 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
427 SWP_NOZORDER|SWP_FRAMECHANGED)
428 * for a visible overlapped window.
429 */
430 static const struct message WmSWP_FrameChangedDeferErase[] = {
431 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
432 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
433 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
434 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
435 { WM_PAINT, sent|parent|optional },
436 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
437 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
438 { WM_PAINT, sent },
439 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
440 { WM_ERASEBKGND, sent|beginpaint|optional },
441 { 0 }
442 };
443
444 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
445 SWP_NOZORDER|SWP_FRAMECHANGED)
446 * for a visible overlapped window without WS_CLIPCHILDREN style set.
447 */
448 static const struct message WmSWP_FrameChanged_noclip[] = {
449 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
450 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
451 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
452 { WM_GETTEXT, sent|parent|defwinproc|optional },
453 { WM_ERASEBKGND, sent|parent|optional },
454 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
455 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
456 { WM_PAINT, sent },
457 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
458 { WM_ERASEBKGND, sent|beginpaint|optional },
459 { 0 }
460 };
461
462 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
463 static const struct message WmShowOverlappedSeq[] = {
464 { WM_SHOWWINDOW, sent|wparam, 1 },
465 { WM_NCPAINT, sent|wparam|optional, 1 },
466 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
467 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
468 { WM_NCPAINT, sent|wparam|optional, 1 },
469 { WM_GETTEXT, sent|defwinproc|optional },
470 { WM_ERASEBKGND, sent|optional },
471 { HCBT_ACTIVATE, hook|optional },
472 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
473 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
474 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
475 { WM_NCPAINT, sent|wparam|optional, 1 },
476 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
477 { WM_NCACTIVATE, sent|wparam|optional, 1 },
478 { WM_GETTEXT, sent|defwinproc|optional },
479 { WM_ACTIVATE, sent|wparam|optional, 1 },
480 { HCBT_SETFOCUS, hook|optional },
481 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
482 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
483 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
484 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
485 { WM_GETTEXT, sent|optional },
486 { WM_NCPAINT, sent|wparam|optional, 1 },
487 { WM_GETTEXT, sent|defwinproc|optional },
488 { WM_ERASEBKGND, sent|optional },
489 /* Win9x adds SWP_NOZORDER below */
490 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
491 { WM_NCCALCSIZE, sent|optional },
492 { WM_GETTEXT, sent|optional },
493 { WM_NCPAINT, sent|optional },
494 { WM_ERASEBKGND, sent|optional },
495 { WM_SYNCPAINT, sent|optional },
496 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
497 * messages. Does that mean that CreateWindow doesn't set initial
498 * window dimensions for overlapped windows?
499 */
500 { WM_SIZE, sent },
501 { WM_MOVE, sent },
502 #endif
503 { WM_PAINT, sent|optional },
504 { WM_NCPAINT, sent|beginpaint|optional },
505 { 0 }
506 };
507 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
508 static const struct message WmShowMaxOverlappedSeq[] = {
509 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
510 { WM_GETMINMAXINFO, sent },
511 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
512 { WM_GETMINMAXINFO, sent|defwinproc },
513 { WM_NCCALCSIZE, sent|wparam, TRUE },
514 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
515 { HCBT_ACTIVATE, hook|optional },
516 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
517 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
518 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
519 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
520 { WM_NCACTIVATE, sent|wparam|optional, 1 },
521 { WM_GETTEXT, sent|defwinproc|optional },
522 { WM_ACTIVATE, sent|wparam|optional, 1 },
523 { HCBT_SETFOCUS, hook|optional },
524 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
525 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
526 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
527 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
528 { WM_GETTEXT, sent|optional },
529 { WM_NCPAINT, sent|wparam|optional, 1 },
530 { WM_GETTEXT, sent|defwinproc|optional },
531 { WM_ERASEBKGND, sent|optional },
532 /* Win9x adds SWP_NOZORDER below */
533 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
534 { WM_MOVE, sent|defwinproc },
535 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
536 { WM_GETTEXT, sent|optional },
537 { WM_NCCALCSIZE, sent|optional },
538 { WM_NCPAINT, sent|optional },
539 { WM_ERASEBKGND, sent|optional },
540 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
541 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
542 { WM_SYNCPAINT, sent|optional },
543 { WM_GETTITLEBARINFOEX, sent|optional },
544 { WM_PAINT, sent|optional },
545 { WM_NCPAINT, sent|beginpaint|optional },
546 { WM_ERASEBKGND, sent|beginpaint|optional },
547 { 0 }
548 };
549 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
550 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
551 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
552 { WM_GETTEXT, sent|optional },
553 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
554 { WM_GETMINMAXINFO, sent|defwinproc },
555 { WM_NCCALCSIZE, sent|wparam, TRUE },
556 { WM_NCPAINT, sent|optional },
557 { WM_GETTEXT, sent|defwinproc|optional },
558 { WM_ERASEBKGND, sent|optional },
559 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
560 { WM_MOVE, sent|defwinproc|optional },
561 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
562 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
563 { WM_NCPAINT, sent|optional },
564 { WM_ERASEBKGND, sent|optional },
565 { WM_PAINT, sent|optional },
566 { WM_GETTITLEBARINFOEX, sent|optional },
567 { WM_NCPAINT, sent|beginpaint|optional },
568 { WM_ERASEBKGND, sent|beginpaint|optional },
569 { 0 }
570 };
571 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
572 static const struct message WmShowRestoreMinOverlappedSeq[] = {
573 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
574 { WM_QUERYOPEN, sent|optional },
575 { WM_GETTEXT, sent|optional },
576 { WM_NCACTIVATE, sent|wparam|optional, 1 },
577 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
578 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
579 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
580 { WM_MOVE, sent|optional },
581 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
582 { WM_GETTEXT, sent|optional },
583 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
584 { WM_GETMINMAXINFO, sent|defwinproc|optional },
585 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
586 { HCBT_ACTIVATE, hook|optional },
587 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
588 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
589 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
590 { WM_NCACTIVATE, sent|wparam|optional, 1 },
591 { WM_GETTEXT, sent|defwinproc|optional },
592 { WM_ACTIVATE, sent|wparam|optional, 1 },
593 { HCBT_SETFOCUS, hook|optional },
594 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
595 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
596 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
597 { WM_GETTEXT, sent|optional },
598 { WM_NCPAINT, sent|wparam|optional, 1 },
599 { WM_GETTEXT, sent|defwinproc|optional },
600 { WM_ERASEBKGND, sent },
601 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
602 { WM_MOVE, sent|defwinproc },
603 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
604 { HCBT_SETFOCUS, hook|optional },
605 { WM_SETFOCUS, sent|wparam|optional, 0 },
606 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
607 { WM_NCPAINT, sent|wparam|optional, 1 },
608 { WM_ERASEBKGND, sent|optional },
609 { HCBT_SETFOCUS, hook|optional },
610 { WM_SETFOCUS, sent|wparam|optional, 0 },
611 { WM_ACTIVATE, sent|wparam, 1 },
612 { WM_GETTEXT, sent|optional },
613 { WM_PAINT, sent|optional },
614 { WM_GETTITLEBARINFOEX, sent|optional },
615 { WM_NCPAINT, sent|beginpaint|optional },
616 { WM_ERASEBKGND, sent|beginpaint|optional },
617 { 0 }
618 };
619 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
620 static const struct message WmShowMinOverlappedSeq[] = {
621 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
622 { HCBT_SETFOCUS, hook|optional },
623 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
624 { WM_KILLFOCUS, sent|optional },
625 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
626 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
627 { WM_GETTEXT, sent|optional },
628 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
629 { WM_GETMINMAXINFO, sent|defwinproc },
630 { WM_NCCALCSIZE, sent|wparam, TRUE },
631 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
632 { WM_NCPAINT, sent|optional },
633 { WM_GETTEXT, sent|defwinproc|optional },
634 { WM_WINDOWPOSCHANGED, sent },
635 { WM_MOVE, sent|defwinproc },
636 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
637 { WM_NCCALCSIZE, sent|optional },
638 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
639 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
640 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
641 { WM_NCACTIVATE, sent|wparam|optional, 0 },
642 { WM_GETTEXT, sent|defwinproc|optional },
643 { WM_ACTIVATE, sent|optional },
644 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
645
646 /* Vista sometimes restores the window right away... */
647 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
648 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
649 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
650 { WM_QUERYOPEN, sent|optional },
651 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
652 { WM_GETMINMAXINFO, sent|optional|defwinproc },
653 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
654 { HCBT_ACTIVATE, hook|optional },
655 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
656 { WM_NCACTIVATE, sent|optional },
657 { WM_GETTEXT, sent|optional },
658 { WM_ACTIVATE, sent|optional|wparam, 1 },
659 { HCBT_SETFOCUS, hook|optional },
660 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
661 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
662 { WM_SETFOCUS, sent|optional },
663 { WM_NCPAINT, sent|optional },
664 { WM_GETTEXT, sent|defwinproc|optional },
665 { WM_ERASEBKGND, sent|optional },
666 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
667 { WM_MOVE, sent|defwinproc|optional },
668 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
669 { WM_ACTIVATE, sent|optional|wparam, 1 },
670 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
671 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
672
673 { WM_PAINT, sent|optional },
674 { WM_NCPAINT, sent|beginpaint|optional },
675 { WM_ERASEBKGND, sent|beginpaint|optional },
676 { 0 }
677 };
678 /* ShowWindow(SW_HIDE) for a visible overlapped window */
679 static const struct message WmHideOverlappedSeq[] = {
680 { WM_SHOWWINDOW, sent|wparam, 0 },
681 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
682 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
683 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
684 { WM_SIZE, sent|optional }, /* XP doesn't send it */
685 { WM_MOVE, sent|optional }, /* XP doesn't send it */
686 { WM_NCACTIVATE, sent|wparam|optional, 0 },
687 { WM_ACTIVATE, sent|wparam|optional, 0 },
688 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
689 { HCBT_SETFOCUS, hook|optional },
690 { WM_KILLFOCUS, sent|wparam|optional, 0 },
691 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
692 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
693 { 0 }
694 };
695 /* DestroyWindow for a visible overlapped window */
696 static const struct message WmDestroyOverlappedSeq[] = {
697 { HCBT_DESTROYWND, hook },
698 { 0x0090, sent|optional },
699 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
700 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
701 { 0x0090, sent|optional },
702 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
703 { WM_NCACTIVATE, sent|optional|wparam, 0 },
704 { WM_ACTIVATE, sent|optional },
705 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
706 { WM_KILLFOCUS, sent|optional|wparam, 0 },
707 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
708 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
709 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
710 { WM_DESTROY, sent },
711 { WM_NCDESTROY, sent },
712 { 0 }
713 };
714 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
715 static const struct message WmCreateMaxPopupSeq[] = {
716 { HCBT_CREATEWND, hook },
717 { WM_NCCREATE, sent },
718 { WM_NCCALCSIZE, sent|wparam, 0 },
719 { WM_CREATE, sent },
720 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
721 { WM_SIZE, sent|wparam, SIZE_RESTORED },
722 { WM_MOVE, sent },
723 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
724 { WM_GETMINMAXINFO, sent },
725 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
726 { WM_NCCALCSIZE, sent|wparam, TRUE },
727 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
728 { WM_MOVE, sent|defwinproc },
729 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
730 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
731 { WM_SHOWWINDOW, sent|wparam, 1 },
732 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
733 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
734 { HCBT_ACTIVATE, hook },
735 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
736 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
737 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
738 { WM_NCPAINT, sent|wparam|optional, 1 },
739 { WM_ERASEBKGND, sent|optional },
740 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
741 { WM_ACTIVATEAPP, sent|wparam, 1 },
742 { WM_NCACTIVATE, sent },
743 { WM_ACTIVATE, sent|wparam, 1 },
744 { HCBT_SETFOCUS, hook },
745 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
746 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
747 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
748 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
749 { WM_GETTEXT, sent|optional },
750 { WM_SYNCPAINT, sent|wparam|optional, 4 },
751 { WM_NCPAINT, sent|wparam|optional, 1 },
752 { WM_ERASEBKGND, sent|optional },
753 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
754 { WM_ERASEBKGND, sent|defwinproc|optional },
755 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
756 { 0 }
757 };
758 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
759 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
760 { HCBT_CREATEWND, hook },
761 { WM_NCCREATE, sent },
762 { WM_NCCALCSIZE, sent|wparam, 0 },
763 { WM_CREATE, sent },
764 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
765 { WM_SIZE, sent|wparam, SIZE_RESTORED },
766 { WM_MOVE, sent },
767 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
768 { WM_GETMINMAXINFO, sent },
769 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
770 { WM_NCCALCSIZE, sent|wparam, TRUE },
771 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
772 { WM_MOVE, sent|defwinproc },
773 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
774 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
775 { 0 }
776 };
777 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
778 static const struct message WmShowMaxPopupResizedSeq_todo[] = {
779 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
780 { WM_GETMINMAXINFO, sent },
781 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
782 { WM_NCCALCSIZE, sent|wparam, TRUE },
783 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
784 { HCBT_ACTIVATE, hook },
785 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
786 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
787 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
788 { WM_NCPAINT, sent|wparam|optional, 1 },
789 { WM_ERASEBKGND, sent|optional },
790 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
791 { WM_ACTIVATEAPP, sent|wparam, 1 },
792 { WM_NCACTIVATE, sent },
793 { WM_ACTIVATE, sent|wparam, 1 },
794 { HCBT_SETFOCUS, hook },
795 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
796 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
797 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
798 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
799 { WM_GETTEXT, sent|optional },
800 { WM_NCPAINT, sent|wparam|optional, 1 },
801 { WM_ERASEBKGND, sent|optional },
802 { WM_WINDOWPOSCHANGED, sent },
803 /* WinNT4.0 sends WM_MOVE */
804 { WM_MOVE, sent|defwinproc|optional },
805 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
806 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
807 { 0 }
808 };
809 static const struct message WmShowMaxPopupResizedSeq[] = {
810 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
811 { WM_GETMINMAXINFO, sent },
812 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
813 { WM_NCCALCSIZE, sent|wparam, TRUE },
814 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
815 { HCBT_ACTIVATE, hook },
816 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
817 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
818 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
819 { WM_NCPAINT, sent|wparam|optional, 1 },
820 { WM_ERASEBKGND, sent|optional },
821 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
822 { WM_ACTIVATEAPP, sent|wparam, 1 },
823 { WM_NCACTIVATE, sent },
824 { WM_ACTIVATE, sent|wparam, 1 },
825 { HCBT_SETFOCUS, hook },
826 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
827 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
828 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
829 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
830 { WM_GETTEXT, sent|optional },
831 { WM_NCPAINT, sent|optional }, /* We'll check WM_NCPAINT behaviour in another test */
832 { WM_ERASEBKGND, sent|optional },
833 { WM_WINDOWPOSCHANGED, sent },
834 /* WinNT4.0 sends WM_MOVE */
835 { WM_MOVE, sent|defwinproc|optional },
836 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
837 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
838 { 0 }
839 };
840 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
841 static const struct message WmShowMaxPopupSeq[] = {
842 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
843 { WM_GETMINMAXINFO, sent },
844 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
845 { WM_NCCALCSIZE, sent|wparam, TRUE },
846 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
847 { HCBT_ACTIVATE, hook },
848 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
849 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
850 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
851 { WM_NCPAINT, sent|wparam|optional, 1 },
852 { WM_ERASEBKGND, sent|optional },
853 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
854 { WM_ACTIVATEAPP, sent|wparam, 1 },
855 { WM_NCACTIVATE, sent },
856 { WM_ACTIVATE, sent|wparam, 1 },
857 { HCBT_SETFOCUS, hook },
858 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
859 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
860 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
861 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
862 { WM_GETTEXT, sent|optional },
863 { WM_SYNCPAINT, sent|wparam|optional, 4 },
864 { WM_NCPAINT, sent|wparam|optional, 1 },
865 { WM_ERASEBKGND, sent|optional },
866 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
867 { WM_ERASEBKGND, sent|defwinproc|optional },
868 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
869 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
870 { 0 }
871 };
872 /* CreateWindow(WS_VISIBLE) for popup window */
873 static const struct message WmCreatePopupSeq[] = {
874 { HCBT_CREATEWND, hook },
875 { WM_NCCREATE, sent },
876 { WM_NCCALCSIZE, sent|wparam, 0 },
877 { WM_CREATE, sent },
878 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
879 { WM_SIZE, sent|wparam, SIZE_RESTORED },
880 { WM_MOVE, sent },
881 { WM_SHOWWINDOW, sent|wparam, 1 },
882 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
883 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
884 { HCBT_ACTIVATE, hook },
885 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
886 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
887 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
888 { WM_NCPAINT, sent|wparam|optional, 1 },
889 { WM_ERASEBKGND, sent|optional },
890 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
891 { WM_ACTIVATEAPP, sent|wparam, 1 },
892 { WM_NCACTIVATE, sent },
893 { WM_ACTIVATE, sent|wparam, 1 },
894 { HCBT_SETFOCUS, hook },
895 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
896 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
897 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
898 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
899 { WM_GETTEXT, sent|optional },
900 { WM_SYNCPAINT, sent|wparam|optional, 4 },
901 { WM_NCPAINT, sent|wparam|optional, 1 },
902 { WM_ERASEBKGND, sent|optional },
903 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
904 { 0 }
905 };
906 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
907 static const struct message WmShowVisMaxPopupSeq[] = {
908 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
909 { WM_GETMINMAXINFO, sent },
910 { WM_GETTEXT, sent|optional },
911 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
912 { WM_GETTEXT, sent|optional },
913 { WM_NCCALCSIZE, sent|wparam, TRUE },
914 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
915 { WM_NCPAINT, sent|wparam|optional, 1 },
916 { WM_ERASEBKGND, sent|optional },
917 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
918 { WM_MOVE, sent|defwinproc },
919 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
920 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
921 { 0 }
922 };
923 /* CreateWindow (for a child popup window, not initially visible) */
924 static const struct message WmCreateChildPopupSeq[] = {
925 { HCBT_CREATEWND, hook },
926 { WM_NCCREATE, sent },
927 { WM_NCCALCSIZE, sent|wparam, 0 },
928 { WM_CREATE, sent },
929 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
930 { WM_SIZE, sent|wparam, SIZE_RESTORED },
931 { WM_MOVE, sent },
932 { 0 }
933 };
934 /* CreateWindow (for a popup window, not initially visible,
935 * which sets WS_VISIBLE in WM_CREATE handler)
936 */
937 static const struct message WmCreateInvisiblePopupSeq[] = {
938 { HCBT_CREATEWND, hook },
939 { WM_NCCREATE, sent },
940 { WM_NCCALCSIZE, sent|wparam, 0 },
941 { WM_CREATE, sent },
942 { WM_STYLECHANGING, sent },
943 { WM_STYLECHANGED, sent },
944 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
945 { WM_SIZE, sent|wparam, SIZE_RESTORED },
946 { WM_MOVE, sent },
947 { 0 }
948 };
949 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
950 * for a popup window with WS_VISIBLE style set
951 */
952 static const struct message WmShowVisiblePopupSeq_2[] = {
953 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
954 { 0 }
955 };
956 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
957 * for a popup window with WS_VISIBLE style set
958 */
959 static const struct message WmShowVisiblePopupSeq_3[] = {
960 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
961 { HCBT_ACTIVATE, hook },
962 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
963 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
964 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
965 { WM_NCACTIVATE, sent },
966 { WM_ACTIVATE, sent|wparam, 1 },
967 { HCBT_SETFOCUS, hook },
968 { WM_KILLFOCUS, sent|parent },
969 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
970 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
971 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
972 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
973 { WM_SETFOCUS, sent|defwinproc },
974 { WM_GETTEXT, sent|optional },
975 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
976 { 0 }
977 };
978 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
979 */
980 static const struct message WmShowPopupExtremeLocationSeq[] = {
981 { HCBT_CREATEWND, hook },
982 { WM_NCCREATE, sent },
983 { WM_NCCALCSIZE, sent|wparam, 0 },
984 { WM_CREATE, sent },
985 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
986 { WM_SIZE, sent|wparam, SIZE_RESTORED },
987 { WM_MOVE, sent },
988 { WM_SHOWWINDOW, sent|wparam, 1 },
989 { WM_WINDOWPOSCHANGING, sent },
990 { HCBT_ACTIVATE, hook },
991 { WM_WINDOWPOSCHANGING, sent|optional },
992 { WM_QUERYNEWPALETTE, sent|optional },
993 { WM_ACTIVATEAPP, sent },
994 { WM_NCACTIVATE, sent },
995 { WM_ACTIVATE, sent },
996 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
997 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
998 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
999 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1000 { HCBT_SETFOCUS, hook },
1001 { WM_SETFOCUS, sent|defwinproc },
1002 { WM_NCPAINT, sent|wparam, 1 },
1003 { WM_ERASEBKGND, sent },
1004 { WM_WINDOWPOSCHANGED, sent },
1005 /* occasionally received on test machines */
1006 { WM_NCPAINT, sent|optional },
1007 { WM_ERASEBKGND, sent|optional },
1008 { 0 }
1009 };
1010 /* CreateWindow (for a popup window with WS_VISIBLE style set)
1011 */
1012 static const struct message WmShowPopupFirstDrawSeq_1[] = {
1013 { HCBT_CREATEWND, hook },
1014 { WM_NCCREATE, sent },
1015 { WM_NCCALCSIZE, sent|wparam, 0 },
1016 { WM_CREATE, sent },
1017 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1018 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1019 { WM_MOVE, sent },
1020 { WM_SHOWWINDOW, sent|wparam, 1 },
1021 { WM_WINDOWPOSCHANGING, sent },
1022 { HCBT_ACTIVATE, hook },
1023 { WM_WINDOWPOSCHANGING, sent|optional },
1024 { WM_QUERYNEWPALETTE, sent|optional },
1025 { WM_ACTIVATEAPP, sent },
1026 { WM_NCACTIVATE, sent },
1027 { WM_ACTIVATE, sent },
1028 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1029 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1030 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1031 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1032 { HCBT_SETFOCUS, hook },
1033 { WM_SETFOCUS, sent|defwinproc },
1034 { WM_NCPAINT, sent|wparam, 1 },
1035 { WM_ERASEBKGND, sent },
1036 { WM_WINDOWPOSCHANGED, sent },
1037 { WM_PAINT, sent },
1038 /* occasionally received on test machines */
1039 { WM_NCPAINT, sent|beginpaint|optional },
1040 { WM_ERASEBKGND, sent|beginpaint|optional },
1041 { 0 }
1042 };
1043 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1044 */
1045 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1046 { HCBT_CREATEWND, hook },
1047 { WM_NCCREATE, sent },
1048 { WM_NCCALCSIZE, sent|wparam, 0 },
1049 { WM_CREATE, sent },
1050 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1051 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1052 { WM_MOVE, sent },
1053 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1054 { WM_GETMINMAXINFO, sent },
1055 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1056 { WM_NCCALCSIZE, sent|wparam, TRUE },
1057 { HCBT_ACTIVATE, hook },
1058 { WM_WINDOWPOSCHANGING, sent|optional },
1059 { WM_NCPAINT, sent|optional|wparam, 1 },
1060 { WM_ERASEBKGND, sent|optional },
1061 { WM_WINDOWPOSCHANGED, sent|optional },
1062 { WM_QUERYNEWPALETTE, sent|optional },
1063 { WM_ACTIVATEAPP, sent },
1064 { WM_NCACTIVATE, sent },
1065 { WM_ACTIVATE, sent },
1066 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1067 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1068 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1069 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1070 { HCBT_SETFOCUS, hook },
1071 { WM_SETFOCUS, sent|defwinproc },
1072 { WM_NCPAINT, sent|wparam, 1 },
1073 { WM_ERASEBKGND, sent },
1074 { WM_WINDOWPOSCHANGED, sent|optional },
1075 { WM_MOVE, sent|defwinproc },
1076 { WM_SIZE, sent|defwinproc, 0 },
1077 { WM_PAINT, sent},
1078 /* occasionally received on test machines */
1079 { WM_NCPAINT, sent|beginpaint|optional },
1080 { WM_ERASEBKGND, sent|beginpaint|optional },
1081 { 0 }
1082 };
1083 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1084 { HCBT_CREATEWND, hook },
1085 { WM_NCCREATE, sent },
1086 { WM_NCCALCSIZE, sent|wparam, 0 },
1087 { WM_CREATE, sent },
1088 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1089 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1090 { WM_MOVE, sent },
1091 { WM_WINDOWPOSCHANGING, sent },
1092 { HCBT_ACTIVATE, hook },
1093 { WM_WINDOWPOSCHANGING, sent|optional },
1094 { WM_QUERYNEWPALETTE, sent|optional },
1095 { WM_ACTIVATEAPP, sent },
1096 { WM_NCACTIVATE, sent },
1097 { WM_ACTIVATE, sent },
1098 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1099 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1100 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1101 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1102 { HCBT_SETFOCUS, hook },
1103 { WM_SETFOCUS, sent|defwinproc },
1104 { WM_NCPAINT, sent|wparam, 1 },
1105 { WM_ERASEBKGND, sent },
1106 { WM_WINDOWPOSCHANGED, sent },
1107 { WM_MOVE, sent|defwinproc },
1108 { 0 }
1109 };
1110 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1111 { HCBT_CREATEWND, hook },
1112 { WM_NCCREATE, sent },
1113 { WM_NCCALCSIZE, sent|wparam, 0 },
1114 { WM_CREATE, sent },
1115 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1116 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1117 { WM_MOVE, sent },
1118 { WM_WINDOWPOSCHANGING, sent },
1119 { HCBT_ACTIVATE, hook },
1120 { WM_QUERYNEWPALETTE, sent|optional },
1121 { WM_WINDOWPOSCHANGING, sent|optional },
1122 { WM_ACTIVATEAPP, sent },
1123 { WM_NCACTIVATE, sent },
1124 { WM_ACTIVATE, sent },
1125 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1126 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1127 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1128 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1129 { HCBT_SETFOCUS, hook },
1130 { WM_SETFOCUS, sent|defwinproc },
1131 { WM_WINDOWPOSCHANGED, sent },
1132 { WM_MOVE, sent|defwinproc },
1133 { 0 }
1134 };
1135 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1136 { HCBT_CREATEWND, hook },
1137 { WM_NCCREATE, sent },
1138 { WM_NCCALCSIZE, sent|wparam, 0 },
1139 { WM_CREATE, sent },
1140 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1141 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1142 { WM_MOVE, sent },
1143 { HCBT_ACTIVATE, hook|optional },
1144 /* Probably shouldn't happen, but not part of this test */
1145 { WM_QUERYNEWPALETTE, sent|optional },
1146 { WM_ACTIVATEAPP, sent|optional },
1147 { WM_NCACTIVATE, sent|optional },
1148 { WM_ACTIVATE, sent|optional },
1149 { HCBT_SETFOCUS, hook|optional },
1150 { WM_SETFOCUS, sent|defwinproc|optional },
1151 { 0 }
1152 };
1153 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1154 { HCBT_CREATEWND, hook },
1155 { WM_NCCREATE, sent },
1156 { WM_NCCALCSIZE, sent|wparam, 0 },
1157 { WM_CREATE, sent },
1158 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1159 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1160 { WM_MOVE, sent },
1161 { WM_WINDOWPOSCHANGING, sent },
1162 { HCBT_ACTIVATE, hook },
1163 { WM_WINDOWPOSCHANGING, sent|optional },
1164 { WM_QUERYNEWPALETTE, sent|optional },
1165 { WM_ACTIVATEAPP, sent },
1166 { WM_NCACTIVATE, sent },
1167 { WM_ACTIVATE, sent },
1168 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1169 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1170 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1171 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1172 { HCBT_SETFOCUS, hook },
1173 { WM_SETFOCUS, sent|defwinproc },
1174 { WM_NCPAINT, sent|wparam, 1 },
1175 { WM_ERASEBKGND, sent },
1176 { WM_WINDOWPOSCHANGED, sent },
1177 { 0 }
1178 };
1179 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1180 { HCBT_CREATEWND, hook },
1181 { WM_NCCREATE, sent },
1182 { WM_NCCALCSIZE, sent|wparam, 0 },
1183 { WM_CREATE, sent },
1184 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1185 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1186 { WM_MOVE, sent },
1187 { WM_WINDOWPOSCHANGING, sent },
1188 { HCBT_ACTIVATE, hook },
1189 { WM_WINDOWPOSCHANGING, sent|optional },
1190 { WM_QUERYNEWPALETTE, sent|optional },
1191 { WM_ACTIVATEAPP, sent },
1192 { WM_NCACTIVATE, sent },
1193 { WM_ACTIVATE, sent },
1194 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1195 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1196 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1197 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1198 { HCBT_SETFOCUS, hook },
1199 { WM_SETFOCUS, sent|defwinproc },
1200 { WM_WINDOWPOSCHANGED, sent },
1201 { 0 }
1202 };
1203 static const struct message WmFirstDrawChildSeq1[] = {
1204 { 0 }
1205 };
1206 static const struct message WmFirstDrawChildSeq2[] = {
1207 { WM_NCPAINT, sent|wparam, 1 },
1208 { WM_ERASEBKGND, sent },
1209 /* occasionally received on test machines */
1210 { WM_NCPAINT, sent|optional },
1211 { WM_ERASEBKGND, sent|optional },
1212 { 0 }
1213 };
1214 /* CreateWindow (for child window, not initially visible) */
1215 static const struct message WmCreateChildSeq[] = {
1216 { HCBT_CREATEWND, hook },
1217 { WM_NCCREATE, sent },
1218 /* child is inserted into parent's child list after WM_NCCREATE returns */
1219 { WM_NCCALCSIZE, sent|wparam, 0 },
1220 { WM_CREATE, sent },
1221 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1222 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1223 { WM_MOVE, sent },
1224 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1225 { 0 }
1226 };
1227 /* CreateWindow (for maximized child window, not initially visible) */
1228 static const struct message WmCreateMaximizedChildSeq[] = {
1229 { HCBT_CREATEWND, hook },
1230 { WM_NCCREATE, sent },
1231 { WM_NCCALCSIZE, sent|wparam, 0 },
1232 { WM_CREATE, sent },
1233 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1234 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1235 { WM_MOVE, sent },
1236 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1237 { WM_GETMINMAXINFO, sent },
1238 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1239 { WM_NCCALCSIZE, sent|wparam, 1 },
1240 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1241 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1242 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1243 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1244 { 0 }
1245 };
1246 /* CreateWindow (for a child window, initially visible) */
1247 static const struct message WmCreateVisibleChildSeq[] = {
1248 { HCBT_CREATEWND, hook },
1249 { WM_NCCREATE, sent },
1250 /* child is inserted into parent's child list after WM_NCCREATE returns */
1251 { WM_NCCALCSIZE, sent|wparam, 0 },
1252 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1253 { WM_CREATE, sent },
1254 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1255 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1256 { WM_MOVE, sent },
1257 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1258 { WM_SHOWWINDOW, sent|wparam, 1 },
1259 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1260 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1261 { WM_ERASEBKGND, sent|parent|optional },
1262 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1263 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1264 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1265 { 0 }
1266 };
1267 /* ShowWindow(SW_SHOW) for a not visible child window */
1268 static const struct message WmShowChildSeq[] = {
1269 { WM_SHOWWINDOW, sent|wparam, 1 },
1270 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1271 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1272 { WM_ERASEBKGND, sent|parent|optional },
1273 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1274 { 0 }
1275 };
1276 /* ShowWindow(SW_HIDE) for a visible child window */
1277 static const struct message WmHideChildSeq[] = {
1278 { WM_SHOWWINDOW, sent|wparam, 0 },
1279 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1280 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1281 { WM_ERASEBKGND, sent|parent|optional },
1282 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1283 { 0 }
1284 };
1285 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1286 static const struct message WmHideChildSeq2[] = {
1287 { WM_SHOWWINDOW, sent|wparam, 0 },
1288 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1289 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1290 { WM_ERASEBKGND, sent|parent|optional },
1291 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1292 { 0 }
1293 };
1294 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1295 * for a not visible child window
1296 */
1297 static const struct message WmShowChildSeq_2[] = {
1298 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1299 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1300 { WM_CHILDACTIVATE, sent },
1301 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1302 { 0 }
1303 };
1304 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1305 * for a not visible child window
1306 */
1307 static const struct message WmShowChildSeq_3[] = {
1308 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1309 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1310 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1311 { 0 }
1312 };
1313 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1314 * for a visible child window with a caption
1315 */
1316 static const struct message WmShowChildSeq_4[] = {
1317 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1318 { WM_CHILDACTIVATE, sent },
1319 { 0 }
1320 };
1321 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1322 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1323 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1324 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1325 { WM_NCCALCSIZE, sent|wparam, 1 },
1326 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1327 { WM_CHILDACTIVATE, sent|optional },
1328 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1329 { WM_MOVE, sent|defwinproc },
1330 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1331 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1332 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1333 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1334 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1335 { WM_GETTEXT, sent|optional },
1336 { 0 }
1337 };
1338 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1339 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1340 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1341 { 0 }
1342 };
1343 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1344 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1345 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1346 { WM_GETMINMAXINFO, sent },
1347 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1348 { WM_NCCALCSIZE, sent|wparam, 1 },
1349 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1350 { WM_CHILDACTIVATE, sent },
1351 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1352 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1353 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1354 { 0 }
1355 };
1356 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1357 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1358 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1359 { 0 }
1360 };
1361 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1362 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1363 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1364 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1365 { WM_NCCALCSIZE, sent|wparam, 1 },
1366 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1367 { WM_CHILDACTIVATE, sent },
1368 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1369 { WM_MOVE, sent|defwinproc },
1370 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1371 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1372 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1373 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1374 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1375 { WM_GETTEXT, sent|optional },
1376 { 0 }
1377 };
1378 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1379 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1380 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1381 { 0 }
1382 };
1383 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1384 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1385 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1386 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1387 { WM_NCCALCSIZE, sent|wparam, 1 },
1388 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1389 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1390 { WM_MOVE, sent|defwinproc },
1391 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1392 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1393 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1394 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1395 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1396 { WM_GETTEXT, sent|optional },
1397 { 0 }
1398 };
1399 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1400 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1401 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1402 { 0 }
1403 };
1404 /* ShowWindow(SW_SHOW) for child with invisible parent */
1405 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1406 { WM_SHOWWINDOW, sent|wparam, 1 },
1407 { 0 }
1408 };
1409 /* ShowWindow(SW_HIDE) for child with invisible parent */
1410 static const struct message WmHideChildInvisibleParentSeq[] = {
1411 { WM_SHOWWINDOW, sent|wparam, 0 },
1412 { 0 }
1413 };
1414 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1415 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1416 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1417 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1418 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1419 { 0 }
1420 };
1421 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1422 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1423 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1424 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1425 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1426 { 0 }
1427 };
1428 /* DestroyWindow for a visible child window */
1429 static const struct message WmDestroyChildSeq[] = {
1430 { HCBT_DESTROYWND, hook },
1431 { 0x0090, sent|optional },
1432 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1433 { WM_SHOWWINDOW, sent|wparam, 0 },
1434 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1435 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1436 { WM_ERASEBKGND, sent|parent|optional },
1437 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1438 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1439 { WM_KILLFOCUS, sent },
1440 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1441 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1442 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1443 { WM_SETFOCUS, sent|parent },
1444 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1445 { WM_DESTROY, sent },
1446 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1447 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1448 { WM_NCDESTROY, sent },
1449 { 0 }
1450 };
1451 /* visible child window destroyed by thread exit */
1452 static const struct message WmExitThreadSeq[] = {
1453 { WM_NCDESTROY, sent }, /* actually in grandchild */
1454 { WM_PAINT, sent|parent },
1455 { WM_ERASEBKGND, sent|parent|beginpaint },
1456 { 0 }
1457 };
1458 /* DestroyWindow for a visible child window with invisible parent */
1459 static const struct message WmDestroyInvisibleChildSeq[] = {
1460 { HCBT_DESTROYWND, hook },
1461 { 0x0090, sent|optional },
1462 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1463 { WM_SHOWWINDOW, sent|wparam, 0 },
1464 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1465 { WM_DESTROY, sent },
1466 { WM_NCDESTROY, sent },
1467 { 0 }
1468 };
1469 /* Resizing child window with MoveWindow (32) */
1470 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1471 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1472 { WM_NCCALCSIZE, sent|wparam, 1 },
1473 { WM_ERASEBKGND, sent|parent|optional },
1474 { WM_ERASEBKGND, sent|optional },
1475 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1476 { WM_MOVE, sent|defwinproc },
1477 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1478 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1479 { 0 }
1480 };
1481 /* Creation of a custom dialog (32) */
1482 static const struct message WmCreateCustomDialogSeq[] = {
1483 { HCBT_CREATEWND, hook },
1484 { WM_GETMINMAXINFO, sent },
1485 { WM_NCCREATE, sent },
1486 { WM_NCCALCSIZE, sent|wparam, 0 },
1487 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1488 { WM_CREATE, sent },
1489 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1490 { WM_NOTIFYFORMAT, sent|optional },
1491 { WM_QUERYUISTATE, sent|optional },
1492 { WM_WINDOWPOSCHANGING, sent|optional },
1493 { WM_GETMINMAXINFO, sent|optional },
1494 { WM_NCCALCSIZE, sent|optional },
1495 { WM_WINDOWPOSCHANGED, sent|optional },
1496 { WM_SHOWWINDOW, sent|wparam, 1 },
1497 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1498 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1499 { HCBT_ACTIVATE, hook },
1500 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1501
1502
1503 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1504
1505 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1506
1507 { WM_NCACTIVATE, sent },
1508 { WM_GETTEXT, sent|optional|defwinproc },
1509 { WM_GETTEXT, sent|optional|defwinproc },
1510 { WM_GETTEXT, sent|optional|defwinproc },
1511 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1512 { WM_ACTIVATE, sent|wparam, 1 },
1513 { WM_GETTEXT, sent|optional },
1514 { WM_KILLFOCUS, sent|parent },
1515 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1516 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1517 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1518 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1519 { WM_SETFOCUS, sent },
1520 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1521 { WM_NCPAINT, sent|wparam, 1 },
1522 { WM_GETTEXT, sent|optional|defwinproc },
1523 { WM_GETTEXT, sent|optional|defwinproc },
1524 { WM_ERASEBKGND, sent },
1525 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1526 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1527 { WM_GETTEXT, sent|optional },
1528 { WM_GETTEXT, sent|optional },
1529 { WM_NCCALCSIZE, sent|optional },
1530 { WM_NCPAINT, sent|optional },
1531 { WM_GETTEXT, sent|optional|defwinproc },
1532 { WM_GETTEXT, sent|optional|defwinproc },
1533 { WM_ERASEBKGND, sent|optional },
1534 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1535 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1536 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1537 { WM_MOVE, sent },
1538 { 0 }
1539 };
1540 /* Calling EndDialog for a custom dialog (32) */
1541 static const struct message WmEndCustomDialogSeq[] = {
1542 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1543 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1544 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1545 { WM_GETTEXT, sent|optional },
1546 { HCBT_ACTIVATE, hook },
1547 { WM_NCACTIVATE, sent|wparam, 0 },
1548 { WM_GETTEXT, sent|optional|defwinproc },
1549 { WM_GETTEXT, sent|optional|defwinproc },
1550 { WM_ACTIVATE, sent|wparam, 0 },
1551 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1552 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1553 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1554 { WM_GETTEXT, sent|optional|defwinproc },
1555 { WM_GETTEXT, sent|optional|defwinproc },
1556 { HCBT_SETFOCUS, hook },
1557 { WM_KILLFOCUS, sent },
1558 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1559 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1560 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1561 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1562 { WM_SETFOCUS, sent|parent|defwinproc },
1563 { 0 }
1564 };
1565 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1566 static const struct message WmShowCustomDialogSeq[] = {
1567 { WM_SHOWWINDOW, sent|wparam, 1 },
1568 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1569 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1570 { HCBT_ACTIVATE, hook },
1571 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1572
1573 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1574
1575 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1576 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1577 { WM_NCACTIVATE, sent },
1578 { WM_ACTIVATE, sent|wparam, 1 },
1579 { WM_GETTEXT, sent|optional },
1580
1581 { WM_KILLFOCUS, sent|parent },
1582 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1583 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1584 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1585 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1586 { WM_SETFOCUS, sent },
1587 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1588 { WM_NCPAINT, sent|wparam, 1 },
1589 { WM_ERASEBKGND, sent },
1590 { WM_CTLCOLORDLG, sent|defwinproc },
1591 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1592 { 0 }
1593 };
1594 /* Creation and destruction of a modal dialog (32) */
1595 static const struct message WmModalDialogSeq[] = {
1596 { WM_CANCELMODE, sent|parent },
1597 { HCBT_SETFOCUS, hook },
1598 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1599 { WM_KILLFOCUS, sent|parent },
1600 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1601 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1602 { WM_ENABLE, sent|parent|wparam, 0 },
1603 { HCBT_CREATEWND, hook },
1604 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1605 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1606 { WM_SETFONT, sent },
1607 { WM_INITDIALOG, sent },
1608 { WM_CHANGEUISTATE, sent|optional },
1609 { WM_UPDATEUISTATE, sent|optional },
1610 { WM_SHOWWINDOW, sent },
1611 { HCBT_ACTIVATE, hook },
1612 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1613 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1614 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1615 { WM_NCACTIVATE, sent },
1616 { WM_GETTEXT, sent|optional },
1617 { WM_ACTIVATE, sent|wparam, 1 },
1618 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1619 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1620 { WM_NCPAINT, sent|optional },
1621 { WM_GETTEXT, sent|optional },
1622 { WM_ERASEBKGND, sent|optional },
1623 { WM_CTLCOLORDLG, sent|optional },
1624 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1625 { WM_GETTEXT, sent|optional },
1626 { WM_NCCALCSIZE, sent|optional },
1627 { WM_NCPAINT, sent|optional },
1628 { WM_GETTEXT, sent|optional },
1629 { WM_ERASEBKGND, sent|optional },
1630 { WM_CTLCOLORDLG, sent|optional },
1631 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1632 { WM_PAINT, sent|optional },
1633 { WM_CTLCOLORBTN, sent|optional },
1634 { WM_GETTITLEBARINFOEX, sent|optional },
1635 { WM_ENTERIDLE, sent|parent|optional },
1636 { WM_ENTERIDLE, sent|parent|optional },
1637 { WM_ENTERIDLE, sent|parent|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_TIMER, sent },
1656 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1657 { WM_ENABLE, sent|parent|wparam, 1 },
1658 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1659 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1660 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1661 { WM_GETTEXT, sent|optional },
1662 { HCBT_ACTIVATE, hook },
1663 { WM_NCACTIVATE, sent|wparam, 0 },
1664 { WM_GETTEXT, sent|optional },
1665 { WM_ACTIVATE, sent|wparam, 0 },
1666 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1667 { WM_WINDOWPOSCHANGING, sent|optional },
1668 { WM_WINDOWPOSCHANGED, sent|optional },
1669 { HCBT_SETFOCUS, hook },
1670 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1671 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1672 { WM_SETFOCUS, sent|parent|defwinproc },
1673 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1674 { HCBT_DESTROYWND, hook },
1675 { 0x0090, sent|optional },
1676 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1677 { WM_DESTROY, sent },
1678 { WM_NCDESTROY, sent },
1679 { 0 }
1680 };
1681 static const struct message WmModalDialogSeq_2[] = {
1682 { WM_CANCELMODE, sent },
1683 { HCBT_SETFOCUS, hook },
1684 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1685 { WM_KILLFOCUS, sent },
1686 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1687 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1688 { WM_ENABLE, sent|wparam, 0 },
1689 { HCBT_CREATEWND, hook },
1690 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1691 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1692 { WM_SETFONT, sent },
1693 { WM_INITDIALOG, sent },
1694 { WM_CHANGEUISTATE, sent|optional },
1695 { WM_UPDATEUISTATE, sent|optional },
1696 { WM_ENABLE, sent|wparam, 1 },
1697 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1698 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1699 { WM_CHANGEUISTATE, sent|optional },
1700 { WM_UPDATEUISTATE, sent|optional },
1701 { HCBT_DESTROYWND, hook },
1702 { 0x0090, sent|optional },
1703 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1704 { WM_DESTROY, sent },
1705 { WM_NCDESTROY, sent },
1706 { 0 }
1707 };
1708 /* SetMenu for NonVisible windows with size change*/
1709 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1710 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1711 { WM_NCCALCSIZE, sent|wparam, 1 },
1712 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1713 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1714 { WM_MOVE, sent|defwinproc },
1715 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1716 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1717 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1718 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1719 { WM_GETTEXT, sent|optional },
1720 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1721 { 0 }
1722 };
1723 /* SetMenu for NonVisible windows with no size change */
1724 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1725 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1726 { WM_NCCALCSIZE, sent|wparam, 1 },
1727 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1728 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1729 { 0 }
1730 };
1731 /* SetMenu for Visible windows with size change */
1732 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1733 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1734 { WM_NCCALCSIZE, sent|wparam, 1 },
1735 { 0x0093, sent|defwinproc|optional },
1736 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1737 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1738 { 0x0093, sent|defwinproc|optional },
1739 { 0x0093, sent|defwinproc|optional },
1740 { 0x0091, sent|defwinproc|optional },
1741 { 0x0092, sent|defwinproc|optional },
1742 { WM_GETTEXT, sent|defwinproc|optional },
1743 { WM_ERASEBKGND, sent|optional },
1744 { WM_ACTIVATE, sent|optional },
1745 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1746 { WM_MOVE, sent|defwinproc },
1747 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1748 { 0x0093, sent|optional },
1749 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1750 { 0x0093, sent|defwinproc|optional },
1751 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1752 { 0x0093, sent|defwinproc|optional },
1753 { 0x0093, sent|defwinproc|optional },
1754 { 0x0091, sent|defwinproc|optional },
1755 { 0x0092, sent|defwinproc|optional },
1756 { WM_ERASEBKGND, sent|optional },
1757 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1758 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1759 { 0 }
1760 };
1761 /* SetMenu for Visible windows with no size change */
1762 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1763 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1764 { WM_NCCALCSIZE, sent|wparam, 1 },
1765 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1766 { WM_GETTEXT, sent|defwinproc|optional },
1767 { WM_ERASEBKGND, sent|optional },
1768 { WM_ACTIVATE, sent|optional },
1769 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1770 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1771 { 0 }
1772 };
1773 /* DrawMenuBar for a visible window */
1774 static const struct message WmDrawMenuBarSeq[] =
1775 {
1776 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1777 { WM_NCCALCSIZE, sent|wparam, 1 },
1778 { 0x0093, sent|defwinproc|optional },
1779 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1780 { 0x0093, sent|defwinproc|optional },
1781 { 0x0093, sent|defwinproc|optional },
1782 { 0x0091, sent|defwinproc|optional },
1783 { 0x0092, sent|defwinproc|optional },
1784 { WM_GETTEXT, sent|defwinproc|optional },
1785 { WM_ERASEBKGND, sent|optional },
1786 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1787 { 0x0093, sent|optional },
1788 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1789 { 0 }
1790 };
1791
1792 static const struct message WmSetRedrawFalseSeq[] =
1793 {
1794 { WM_SETREDRAW, sent|wparam, 0 },
1795 { 0 }
1796 };
1797
1798 static const struct message WmSetRedrawTrueSeq[] =
1799 {
1800 { WM_SETREDRAW, sent|wparam, 1 },
1801 { 0 }
1802 };
1803
1804 static const struct message WmEnableWindowSeq_1[] =
1805 {
1806 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1807 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1808 { HCBT_SETFOCUS, hook|optional },
1809 { WM_KILLFOCUS, sent|optional },
1810 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1811 { 0 }
1812 };
1813
1814 static const struct message WmEnableWindowSeq_2[] =
1815 {
1816 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1817 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1818 { 0 }
1819 };
1820
1821 static const struct message WmEnableWindowSeq_3[] =
1822 {
1823 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1824 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1825 { 0 }
1826 };
1827
1828 static const struct message WmEnableWindowSeq_4[] =
1829 {
1830 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1831 { 0 }
1832 };
1833
1834 static const struct message WmGetScrollRangeSeq[] =
1835 {
1836 { SBM_GETRANGE, sent },
1837 { 0 }
1838 };
1839 static const struct message WmGetScrollInfoSeq[] =
1840 {
1841 { SBM_GETSCROLLINFO, sent },
1842 { 0 }
1843 };
1844 static const struct message WmSetScrollRangeSeq[] =
1845 {
1846 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1847 sends SBM_SETSCROLLINFO.
1848 */
1849 { SBM_SETSCROLLINFO, sent },
1850 { 0 }
1851 };
1852 /* SetScrollRange for a window without a non-client area */
1853 static const struct message WmSetScrollRangeHSeq_empty[] =
1854 {
1855 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1856 { 0 }
1857 };
1858 static const struct message WmSetScrollRangeVSeq_empty[] =
1859 {
1860 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1861 { 0 }
1862 };
1863 static const struct message WmSetScrollRangeHVSeq[] =
1864 {
1865 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1866 { WM_NCCALCSIZE, sent|wparam, 1 },
1867 { WM_GETTEXT, sent|defwinproc|optional },
1868 { WM_ERASEBKGND, sent|optional },
1869 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1870 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1871 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1872 { 0 }
1873 };
1874 /* SetScrollRange for a window with a non-client area */
1875 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1876 {
1877 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1878 { WM_NCCALCSIZE, sent|wparam, 1 },
1879 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1880 { WM_NCPAINT, sent|optional },
1881 { WM_STYLECHANGING, sent|defwinproc|optional },
1882 { WM_STYLECHANGED, sent|defwinproc|optional },
1883 { WM_STYLECHANGING, sent|defwinproc|optional },
1884 { WM_STYLECHANGED, sent|defwinproc|optional },
1885 { WM_STYLECHANGING, sent|defwinproc|optional },
1886 { WM_STYLECHANGED, sent|defwinproc|optional },
1887 { WM_STYLECHANGING, sent|defwinproc|optional },
1888 { WM_STYLECHANGED, sent|defwinproc|optional },
1889 { WM_GETTEXT, sent|defwinproc|optional },
1890 { WM_GETTEXT, sent|defwinproc|optional },
1891 { WM_ERASEBKGND, sent|optional },
1892 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1893 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1894 { WM_SIZE, sent|defwinproc|optional },
1895 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1896 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1897 { WM_GETTEXT, sent|optional },
1898 { WM_GETTEXT, sent|optional },
1899 { WM_GETTEXT, sent|optional },
1900 { WM_GETTEXT, sent|optional },
1901 { 0 }
1902 };
1903 /* test if we receive the right sequence of messages */
1904 /* after calling ShowWindow( SW_SHOWNA) */
1905 static const struct message WmSHOWNAChildInvisParInvis[] = {
1906 { WM_SHOWWINDOW, sent|wparam, 1 },
1907 { 0 }
1908 };
1909 static const struct message WmSHOWNAChildVisParInvis[] = {
1910 { WM_SHOWWINDOW, sent|wparam, 1 },
1911 { 0 }
1912 };
1913 static const struct message WmSHOWNAChildVisParVis[] = {
1914 { WM_SHOWWINDOW, sent|wparam, 1 },
1915 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1916 { 0 }
1917 };
1918 static const struct message WmSHOWNAChildInvisParVis[] = {
1919 { WM_SHOWWINDOW, sent|wparam, 1 },
1920 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1921 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1922 { WM_ERASEBKGND, sent|optional },
1923 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1924 { 0 }
1925 };
1926 static const struct message WmSHOWNATopVisible[] = {
1927 { WM_SHOWWINDOW, sent|wparam, 1 },
1928 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1929 { WM_NCPAINT, sent|wparam|optional, 1 },
1930 { WM_GETTEXT, sent|defwinproc|optional },
1931 { WM_ERASEBKGND, sent|optional },
1932 { WM_WINDOWPOSCHANGED, sent|optional },
1933 { 0 }
1934 };
1935 static const struct message WmSHOWNATopInvisible[] = {
1936 { WM_NOTIFYFORMAT, sent|optional },
1937 { WM_QUERYUISTATE, sent|optional },
1938 { WM_WINDOWPOSCHANGING, sent|optional },
1939 { WM_GETMINMAXINFO, sent|optional },
1940 { WM_NCCALCSIZE, sent|optional },
1941 { WM_WINDOWPOSCHANGED, sent|optional },
1942 { WM_SHOWWINDOW, sent|wparam, 1 },
1943 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1944 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1945 { WM_NCPAINT, sent|wparam|optional, 1 },
1946 { WM_GETTEXT, sent|defwinproc|optional },
1947 { WM_ERASEBKGND, sent|optional },
1948 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1949 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1950 { WM_NCPAINT, sent|wparam|optional, 1 },
1951 { WM_ERASEBKGND, sent|optional },
1952 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1953 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1954 { WM_MOVE, sent },
1955 { 0 }
1956 };
1957
1958 static const struct message WmTrackPopupMenu[] = {
1959 { HCBT_CREATEWND, hook },
1960 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1961 { WM_INITMENU, sent|lparam, 0, 0 },
1962 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1963 { 0x0093, sent|optional },
1964 { 0x0094, sent|optional },
1965 { 0x0094, sent|optional },
1966 { WM_ENTERIDLE, sent|wparam, 2 },
1967 { WM_CAPTURECHANGED, sent },
1968 { HCBT_DESTROYWND, hook },
1969 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1970 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1971 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1972 { 0 }
1973 };
1974
1975 static const struct message WmTrackPopupMenuEsc[] = {
1976 { 0 }
1977 };
1978
1979 static const struct message WmTrackPopupMenuCapture[] = {
1980 { HCBT_CREATEWND, hook },
1981 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1982 { WM_CAPTURECHANGED, sent },
1983 { WM_INITMENU, sent|lparam, 0, 0 },
1984 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1985 { 0x0093, sent|optional },
1986 { 0x0094, sent|optional },
1987 { 0x0094, sent|optional },
1988 { WM_ENTERIDLE, sent|wparam, 2 },
1989 { WM_CAPTURECHANGED, sent },
1990 { HCBT_DESTROYWND, hook },
1991 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1992 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1993 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1994 { 0 }
1995 };
1996
1997 static const struct message WmTrackPopupMenuEmpty[] = {
1998 { HCBT_CREATEWND, hook },
1999 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2000 { WM_INITMENU, sent|lparam, 0, 0 },
2001 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2002 { 0x0093, sent|optional },
2003 { 0x0094, sent|optional },
2004 { 0x0094, sent|optional },
2005 { WM_CAPTURECHANGED, sent },
2006 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2007 { HCBT_DESTROYWND, hook },
2008 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2009 { 0 }
2010 };
2011
2012 static const struct message WmTrackPopupMenuAbort[] = {
2013 { HCBT_CREATEWND, hook },
2014 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2015 { WM_INITMENU, sent|lparam, 0, 0 },
2016 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2017 { 0x0093, sent|optional },
2018 { 0x0094, sent|optional },
2019 { 0x0094, sent|optional },
2020 { WM_CAPTURECHANGED, sent },
2021 { HCBT_DESTROYWND, hook },
2022 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2023 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2024 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2025 { 0 }
2026 };
2027
2028 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2029 static int sequence_cnt, sequence_size;
2030 static struct recvd_message* sequence;
2031 static int log_all_parent_messages;
2032 static CRITICAL_SECTION sequence_cs;
2033
2034 /* user32 functions */
2035 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2036 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2037 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2038 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2039 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2040 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2041 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2042 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2043 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2044 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2045 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2046 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2047 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2048 /* kernel32 functions */
2049 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2050
2051 static void init_procs(void)
2052 {
2053 HMODULE user32 = GetModuleHandleA("user32.dll");
2054 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2055
2056 #define GET_PROC(dll, func) \
2057 p ## func = (void*)GetProcAddress(dll, #func); \
2058 if(!p ## func) { \
2059 trace("GetProcAddress(%s) failed\n", #func); \
2060 }
2061
2062 GET_PROC(user32, GetAncestor)
2063 GET_PROC(user32, GetMenuInfo)
2064 GET_PROC(user32, NotifyWinEvent)
2065 GET_PROC(user32, SetMenuInfo)
2066 GET_PROC(user32, SetWinEventHook)
2067 GET_PROC(user32, TrackMouseEvent)
2068 GET_PROC(user32, UnhookWinEvent)
2069 GET_PROC(user32, GetMonitorInfoA)
2070 GET_PROC(user32, MonitorFromPoint)
2071 GET_PROC(user32, UpdateLayeredWindow)
2072 GET_PROC(user32, SetSystemTimer)
2073 GET_PROC(user32, KillSystemTimer)
2074 GET_PROC(user32, SetCoalescableTimer)
2075
2076 GET_PROC(kernel32, GetCPInfoExA)
2077
2078 #undef GET_PROC
2079 }
2080
2081 static const char *get_winpos_flags(UINT flags)
2082 {
2083 static char buffer[300];
2084
2085 buffer[0] = 0;
2086 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2087 DUMP( SWP_SHOWWINDOW );
2088 DUMP( SWP_HIDEWINDOW );
2089 DUMP( SWP_NOACTIVATE );
2090 DUMP( SWP_FRAMECHANGED );
2091 DUMP( SWP_NOCOPYBITS );
2092 DUMP( SWP_NOOWNERZORDER );
2093 DUMP( SWP_NOSENDCHANGING );
2094 DUMP( SWP_DEFERERASE );
2095 DUMP( SWP_ASYNCWINDOWPOS );
2096 DUMP( SWP_NOZORDER );
2097 DUMP( SWP_NOREDRAW );
2098 DUMP( SWP_NOSIZE );
2099 DUMP( SWP_NOMOVE );
2100 DUMP( SWP_NOCLIENTSIZE );
2101 DUMP( SWP_NOCLIENTMOVE );
2102 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2103 return buffer + 1;
2104 #undef DUMP
2105 }
2106
2107 static BOOL ignore_message( UINT message )
2108 {
2109 /* these are always ignored */
2110 return (message >= 0xc000 ||
2111 message == WM_GETICON ||
2112 message == WM_GETOBJECT ||
2113 message == WM_TIMECHANGE ||
2114 message == WM_DISPLAYCHANGE ||
2115 message == WM_DEVICECHANGE ||
2116 message == WM_DWMNCRENDERINGCHANGED);
2117 }
2118
2119 static unsigned hash_Ly_W(const WCHAR *str)
2120 {
2121 unsigned hash = 0;
2122
2123 for (; *str; str++)
2124 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2125
2126 return hash;
2127 }
2128
2129 static unsigned hash_Ly(const char *str)
2130 {
2131 unsigned hash = 0;
2132
2133 for (; *str; str++)
2134 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2135
2136 return hash;
2137 }
2138
2139 #define add_message(msg) add_message_(__LINE__,msg);
2140 static void add_message_(int line, const struct recvd_message *msg)
2141 {
2142 struct recvd_message *seq;
2143
2144 EnterCriticalSection( &sequence_cs );
2145 if (!sequence)
2146 {
2147 sequence_size = 10;
2148 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2149 }
2150 if (sequence_cnt == sequence_size)
2151 {
2152 sequence_size *= 2;
2153 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2154 }
2155 assert(sequence);
2156
2157 seq = &sequence[sequence_cnt++];
2158 seq->hwnd = msg->hwnd;
2159 seq->message = msg->message;
2160 seq->flags = msg->flags;
2161 seq->wParam = msg->wParam;
2162 seq->lParam = msg->lParam;
2163 seq->line = line;
2164 seq->descr = msg->descr;
2165 seq->output[0] = 0;
2166 LeaveCriticalSection( &sequence_cs );
2167
2168 if (msg->descr)
2169 {
2170 if (msg->flags & hook)
2171 {
2172 static const char * const CBT_code_name[10] =
2173 {
2174 "HCBT_MOVESIZE",
2175 "HCBT_MINMAX",
2176 "HCBT_QS",
2177 "HCBT_CREATEWND",
2178 "HCBT_DESTROYWND",
2179 "HCBT_ACTIVATE",
2180 "HCBT_CLICKSKIPPED",
2181 "HCBT_KEYSKIPPED",
2182 "HCBT_SYSCOMMAND",
2183 "HCBT_SETFOCUS"
2184 };
2185 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2186
2187 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2188 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2189 }
2190 else if (msg->flags & winevent_hook)
2191 {
2192 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2193 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2194 }
2195 else
2196 {
2197 switch (msg->message)
2198 {
2199 case WM_WINDOWPOSCHANGING:
2200 case WM_WINDOWPOSCHANGED:
2201 {
2202 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2203
2204 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2205 msg->descr, msg->hwnd,
2206 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2207 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2208 winpos->x, winpos->y, winpos->cx, winpos->cy,
2209 get_winpos_flags(winpos->flags) );
2210
2211 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2212 * in the high word for internal purposes
2213 */
2214 seq->wParam = winpos->flags & 0xffff;
2215 /* We are not interested in the flags that don't match under XP and Win9x */
2216 seq->wParam &= ~SWP_NOZORDER;
2217 break;
2218 }
2219
2220 case WM_DRAWITEM:
2221 {
2222 DRAW_ITEM_STRUCT di;
2223 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2224
2225 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2226 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2227 dis->itemID, dis->itemAction, dis->itemState);
2228
2229 di.u.lp = 0;
2230 di.u.item.type = dis->CtlType;
2231 di.u.item.ctl_id = dis->CtlID;
2232 if (dis->CtlType == ODT_LISTBOX ||
2233 dis->CtlType == ODT_COMBOBOX ||
2234 dis->CtlType == ODT_MENU)
2235 di.u.item.item_id = dis->itemID;
2236 di.u.item.action = dis->itemAction;
2237 di.u.item.state = dis->itemState;
2238
2239 seq->lParam = di.u.lp;
2240 break;
2241 }
2242
2243 case WM_MEASUREITEM:
2244 {
2245 MEASURE_ITEM_STRUCT mi;
2246 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2247 BOOL is_unicode_data = TRUE;
2248
2249 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2250 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2251 mis->itemID, mis->itemData);
2252
2253 if (mis->CtlType == ODT_LISTBOX)
2254 {
2255 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2256 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2257 }
2258
2259 mi.u.wp = 0;
2260 mi.u.item.CtlType = mis->CtlType;
2261 mi.u.item.CtlID = mis->CtlID;
2262 mi.u.item.itemID = mis->itemID;
2263 mi.u.item.wParam = msg->wParam;
2264 seq->wParam = mi.u.wp;
2265 if (is_unicode_data)
2266 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2267 else
2268 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2269 break;
2270 }
2271
2272 case WM_COMPAREITEM:
2273 {
2274 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2275 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2276 BOOL is_unicode_data = TRUE;
2277
2278 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2279 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2280 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2281 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2282
2283 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2284 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2285 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2286
2287 if (cis->CtlType == ODT_LISTBOX)
2288 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2289
2290 if (is_unicode_data)
2291 {
2292 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2293 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2294 }
2295 else
2296 {
2297 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2298 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2299 }
2300 break;
2301 }
2302
2303 default:
2304 if (msg->message >= 0xc000) return; /* ignore registered messages */
2305 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2306 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2307 }
2308 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2309 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2310 }
2311 }
2312 }
2313
2314 /* try to make sure pending X events have been processed before continuing */
2315 static void flush_events(void)
2316 {
2317 MSG msg;
2318 int diff = 200;
2319 int min_timeout = 100;
2320 DWORD time = GetTickCount() + diff;
2321
2322 while (diff > 0)
2323 {
2324 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2325 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2326 diff = time - GetTickCount();
2327 }
2328 }
2329
2330 static void flush_sequence(void)
2331 {
2332 EnterCriticalSection( &sequence_cs );
2333 HeapFree(GetProcessHeap(), 0, sequence);
2334 sequence = 0;
2335 sequence_cnt = sequence_size = 0;
2336 LeaveCriticalSection( &sequence_cs );
2337 }
2338
2339 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2340 {
2341 const struct recvd_message *actual = sequence;
2342 unsigned int count = 0;
2343
2344 trace_(file, line)("Failed sequence %s:\n", context );
2345 while (expected->message && actual->message)
2346 {
2347 if (actual->output[0])
2348 {
2349 if (expected->flags & hook)
2350 {
2351 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2352 count, expected->message, actual->output );
2353 }
2354 else if (expected->flags & winevent_hook)
2355 {
2356 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2357 count, expected->message, actual->output );
2358 }
2359 else if (expected->flags & kbd_hook)
2360 {
2361 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2362 count, expected->message, actual->output );
2363 }
2364 else
2365 {
2366 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2367 count, expected->message, actual->output );
2368 }
2369 }
2370
2371 if (expected->message == actual->message)
2372 {
2373 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2374 (expected->flags & optional))
2375 {
2376 /* don't match messages if their defwinproc status differs */
2377 expected++;
2378 }
2379 else
2380 {
2381 expected++;
2382 actual++;
2383 }
2384 }
2385 /* silently drop winevent messages if there is no support for them */
2386 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2387 expected++;
2388 else
2389 {
2390 expected++;
2391 actual++;
2392 }
2393 count++;
2394 }
2395
2396 /* optional trailing messages */
2397 while (expected->message && ((expected->flags & optional) ||
2398 ((expected->flags & winevent_hook) && !hEvent_hook)))
2399 {
2400 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2401 expected++;
2402 count++;
2403 }
2404
2405 if (expected->message)
2406 {
2407 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2408 return;
2409 }
2410
2411 while (actual->message && actual->output[0])
2412 {
2413 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2414 actual++;
2415 count++;
2416 }
2417 }
2418
2419 #define ok_sequence( exp, contx, todo) \
2420 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2421
2422
2423 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2424 const char *file, int line)
2425 {
2426 static const struct recvd_message end_of_sequence;
2427 const struct message *expected = expected_list;
2428 const struct recvd_message *actual;
2429 int failcount = 0, dump = 0;
2430 unsigned int count = 0;
2431
2432 add_message(&end_of_sequence);
2433
2434 actual = sequence;
2435
2436 while (expected->message && actual->message)
2437 {
2438 if (expected->message == actual->message &&
2439 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2440 {
2441 if (expected->flags & wparam)
2442 {
2443 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2444 {
2445 todo_wine {
2446 failcount ++;
2447 if (strcmp(winetest_platform, "wine")) dump++;
2448 ok_( file, line) (FALSE,
2449 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2450 context, count, expected->message, expected->wParam, actual->wParam);
2451 }
2452 }
2453 else
2454 {
2455 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2456 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2457 context, count, expected->message, expected->wParam, actual->wParam);
2458 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2459 }
2460
2461 }
2462 if (expected->flags & lparam)
2463 {
2464 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2465 {
2466 todo_wine {
2467 failcount ++;
2468 if (strcmp(winetest_platform, "wine")) dump++;
2469 ok_( file, line) (FALSE,
2470 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2471 context, count, expected->message, expected->lParam, actual->lParam);
2472 }
2473 }
2474 else
2475 {
2476 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2477 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2478 context, count, expected->message, expected->lParam, actual->lParam);
2479 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2480 }
2481 }
2482 if ((expected->flags & optional) &&
2483 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2484 {
2485 /* don't match optional messages if their defwinproc or parent status differs */
2486 expected++;
2487 count++;
2488 continue;
2489 }
2490 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2491 {
2492 todo_wine {
2493 failcount ++;
2494 if (strcmp(winetest_platform, "wine")) dump++;
2495 ok_( file, line) (FALSE,
2496 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2497 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2498 }
2499 }
2500 else
2501 {
2502 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2503 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2504 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2505 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2506 }
2507
2508 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2509 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2510 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2511 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2512
2513 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2514 "%s: %u: the msg 0x%04x should have been %s\n",
2515 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2516 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2517
2518 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2519 "%s: %u: the msg 0x%04x was expected in %s\n",
2520 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2521 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2522
2523 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2524 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2525 context, count, expected->message);
2526 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2527
2528 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2529 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2530 context, count, expected->message);
2531 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2532
2533 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2534 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2535 context, count, expected->message);
2536 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2537
2538 expected++;
2539 actual++;
2540 }
2541 /* silently drop hook messages if there is no support for them */
2542 else if ((expected->flags & optional) ||
2543 ((expected->flags & hook) && !hCBT_hook) ||
2544 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2545 ((expected->flags & kbd_hook) && !hKBD_hook))
2546 expected++;
2547 else if (todo)
2548 {
2549 failcount++;
2550 todo_wine {
2551 if (strcmp(winetest_platform, "wine")) dump++;
2552 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2553 context, count, expected->message, actual->message);
2554 }
2555 goto done;
2556 }
2557 else
2558 {
2559 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2560 context, count, expected->message, actual->message);
2561 dump++;
2562 expected++;
2563 actual++;
2564 }
2565 count++;
2566 }
2567
2568 /* skip all optional trailing messages */
2569 while (expected->message && ((expected->flags & optional) ||
2570 ((expected->flags & hook) && !hCBT_hook) ||
2571 ((expected->flags & winevent_hook) && !hEvent_hook)))
2572 expected++;
2573
2574 if (todo)
2575 {
2576 todo_wine {
2577 if (expected->message || actual->message) {
2578 failcount++;
2579 if (strcmp(winetest_platform, "wine")) dump++;
2580 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2581 context, count, expected->message, actual->message);
2582 }
2583 }
2584 }
2585 else
2586 {
2587 if (expected->message || actual->message)
2588 {
2589 dump++;
2590 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2591 context, count, expected->message, actual->message);
2592 }
2593 }
2594 if( todo && !failcount) /* succeeded yet marked todo */
2595 todo_wine {
2596 if (!strcmp(winetest_platform, "wine")) dump++;
2597 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2598 }
2599
2600 done:
2601 if (dump) dump_sequence(expected_list, context, file, line);
2602 flush_sequence();
2603 }
2604
2605 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2606
2607 /******************************** MDI test **********************************/
2608
2609 /* CreateWindow for MDI frame window, initially visible */
2610 static const struct message WmCreateMDIframeSeq[] = {
2611 { HCBT_CREATEWND, hook },
2612 { WM_GETMINMAXINFO, sent },
2613 { WM_NCCREATE, sent },
2614 { WM_NCCALCSIZE, sent|wparam, 0 },
2615 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2616 { WM_CREATE, sent },
2617 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2618 { WM_NOTIFYFORMAT, sent|optional },
2619 { WM_QUERYUISTATE, sent|optional },
2620 { WM_WINDOWPOSCHANGING, sent|optional },
2621 { WM_GETMINMAXINFO, sent|optional },
2622 { WM_NCCALCSIZE, sent|optional },
2623 { WM_WINDOWPOSCHANGED, sent|optional },
2624 { WM_SHOWWINDOW, sent|wparam, 1 },
2625 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2626 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2627 { HCBT_ACTIVATE, hook },
2628 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2629 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2630 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2631 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2632 { WM_NCACTIVATE, sent },
2633 { WM_GETTEXT, sent|defwinproc|optional },
2634 { WM_ACTIVATE, sent|wparam, 1 },
2635 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2636 { HCBT_SETFOCUS, hook },
2637 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2638 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2639 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2640 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2641 /* Win9x adds SWP_NOZORDER below */
2642 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2643 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2644 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2645 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2646 { WM_MOVE, sent },
2647 { 0 }
2648 };
2649 /* DestroyWindow for MDI frame window, initially visible */
2650 static const struct message WmDestroyMDIframeSeq[] = {
2651 { HCBT_DESTROYWND, hook },
2652 { 0x0090, sent|optional },
2653 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2654 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2655 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2656 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2657 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2658 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2659 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2660 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2661 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2662 { WM_DESTROY, sent },
2663 { WM_NCDESTROY, sent },
2664 { 0 }
2665 };
2666 /* CreateWindow for MDI client window, initially visible */
2667 static const struct message WmCreateMDIclientSeq[] = {
2668 { HCBT_CREATEWND, hook },
2669 { WM_NCCREATE, sent },
2670 { WM_NCCALCSIZE, sent|wparam, 0 },
2671 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2672 { WM_CREATE, sent },
2673 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2674 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2675 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2676 { WM_MOVE, sent },
2677 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2678 { WM_SHOWWINDOW, sent|wparam, 1 },
2679 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2680 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2681 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2682 { 0 }
2683 };
2684 /* ShowWindow(SW_SHOW) for MDI client window */
2685 static const struct message WmShowMDIclientSeq[] = {
2686 { WM_SHOWWINDOW, sent|wparam, 1 },
2687 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2688 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2689 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2690 { 0 }
2691 };
2692 /* ShowWindow(SW_HIDE) for MDI client window */
2693 static const struct message WmHideMDIclientSeq[] = {
2694 { WM_SHOWWINDOW, sent|wparam, 0 },
2695 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2696 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2697 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2698 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2699 { 0 }
2700 };
2701 /* DestroyWindow for MDI client window, initially visible */
2702 static const struct message WmDestroyMDIclientSeq[] = {
2703 { HCBT_DESTROYWND, hook },
2704 { 0x0090, sent|optional },
2705 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2706 { WM_SHOWWINDOW, sent|wparam, 0 },
2707 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2708 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2709 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2710 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2711 { WM_DESTROY, sent },
2712 { WM_NCDESTROY, sent },
2713 { 0 }
2714 };
2715 /* CreateWindow for MDI child window, initially visible */
2716 static const struct message WmCreateMDIchildVisibleSeq[] = {
2717 { HCBT_CREATEWND, hook },
2718 { WM_NCCREATE, sent },
2719 { WM_NCCALCSIZE, sent|wparam, 0 },
2720 { WM_CREATE, sent },
2721 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2722 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2723 { WM_MOVE, sent },
2724 /* Win2k sends wparam set to
2725 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2726 * while Win9x doesn't bother to set child window id according to
2727 * CLIENTCREATESTRUCT.idFirstChild
2728 */
2729 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2730 { WM_SHOWWINDOW, sent|wparam, 1 },
2731 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2732 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2733 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2734 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2735 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2736 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2737 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2738
2739 /* Win9x: message sequence terminates here. */
2740
2741 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2742 { HCBT_SETFOCUS, hook }, /* in MDI client */
2743 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2744 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2745 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2746 { WM_SETFOCUS, sent }, /* in MDI client */
2747 { HCBT_SETFOCUS, hook },
2748 { WM_KILLFOCUS, sent }, /* in MDI client */
2749 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2750 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2751 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2752 { WM_SETFOCUS, sent|defwinproc },
2753 { WM_MDIACTIVATE, sent|defwinproc },
2754 { 0 }
2755 };
2756 /* WM_CHILDACTIVATE sent to disabled window */
2757 static const struct message WmChildActivateDisabledWindowSeq[] = {
2758 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2759 { 0 }
2760 };
2761 /* WM_CHILDACTIVATE sent to enabled window */
2762 static const struct message WmChildActivateWindowSeq[] = {
2763 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2764 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2765 { WM_MDIACTIVATE, sent|defwinproc },
2766 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2767 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2768 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2769 { HCBT_SETFOCUS, hook },
2770 { WM_KILLFOCUS, sent|defwinproc },
2771 { WM_SETFOCUS, sent },
2772 { HCBT_SETFOCUS, hook },
2773 { WM_KILLFOCUS, sent },
2774 { WM_SETFOCUS, sent|defwinproc },
2775 { WM_MDIACTIVATE, sent|defwinproc },
2776 { 0 }
2777 };
2778 /* CreateWindow for MDI child window with invisible parent */
2779 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2780 { HCBT_CREATEWND, hook },
2781 { WM_GETMINMAXINFO, sent },
2782 { WM_NCCREATE, sent },
2783 { WM_NCCALCSIZE, sent|wparam, 0 },
2784 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2785 { WM_CREATE, sent },
2786 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2787 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2788 { WM_MOVE, sent },
2789 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2790 { WM_SHOWWINDOW, sent|wparam, 1 },
2791 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2792 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2793 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2794 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2795
2796 /* Win9x: message sequence terminates here. */
2797
2798 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2799 { HCBT_SETFOCUS, hook }, /* in MDI client */
2800 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2801 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2802 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2803 { WM_SETFOCUS, sent }, /* in MDI client */
2804 { HCBT_SETFOCUS, hook },
2805 { WM_KILLFOCUS, sent }, /* in MDI client */
2806 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2807 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2808 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2809 { WM_SETFOCUS, sent|defwinproc },
2810 { WM_MDIACTIVATE, sent|defwinproc },
2811 { 0 }
2812 };
2813 /* DestroyWindow for MDI child window, initially visible */
2814 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2815 { HCBT_DESTROYWND, hook },
2816 /* Win2k sends wparam set to
2817 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2818 * while Win9x doesn't bother to set child window id according to
2819 * CLIENTCREATESTRUCT.idFirstChild
2820 */
2821 { 0x0090, sent|optional },
2822 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2823 { WM_SHOWWINDOW, sent|wparam, 0 },
2824 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2825 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2826 { WM_ERASEBKGND, sent|parent|optional },
2827 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2828
2829 /* { WM_DESTROY, sent }
2830 * Win9x: message sequence terminates here.
2831 */
2832
2833 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2834 { WM_KILLFOCUS, sent },
2835 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2836 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2837 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2838 { WM_SETFOCUS, sent }, /* in MDI client */
2839
2840 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2841 { WM_KILLFOCUS, sent }, /* in MDI client */
2842 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2843 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2844 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2845 { WM_SETFOCUS, sent }, /* in MDI client */
2846
2847 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2848
2849 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2850 { WM_KILLFOCUS, sent },
2851 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2852 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2853 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2854 { WM_SETFOCUS, sent }, /* in MDI client */
2855
2856 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2857 { WM_KILLFOCUS, sent }, /* in MDI client */
2858 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2859 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2860 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2861 { WM_SETFOCUS, sent }, /* in MDI client */
2862
2863 { WM_DESTROY, sent },
2864
2865 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2866 { WM_KILLFOCUS, sent },
2867 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2868 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2869 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2870 { WM_SETFOCUS, sent }, /* in MDI client */
2871
2872 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2873 { WM_KILLFOCUS, sent }, /* in MDI client */
2874 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2875 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2876 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2877 { WM_SETFOCUS, sent }, /* in MDI client */
2878
2879 { WM_NCDESTROY, sent },
2880 { 0 }
2881 };
2882 /* CreateWindow for MDI child window, initially invisible */
2883 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2884 { HCBT_CREATEWND, hook },
2885 { WM_NCCREATE, sent },
2886 { WM_NCCALCSIZE, sent|wparam, 0 },
2887 { WM_CREATE, sent },
2888 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2889 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2890 { WM_MOVE, sent },
2891 /* Win2k sends wparam set to
2892 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2893 * while Win9x doesn't bother to set child window id according to
2894 * CLIENTCREATESTRUCT.idFirstChild
2895 */
2896 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2897 { 0 }
2898 };
2899 /* DestroyWindow for MDI child window, initially invisible */
2900 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2901 { HCBT_DESTROYWND, hook },
2902 /* Win2k sends wparam set to
2903 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2904 * while Win9x doesn't bother to set child window id according to
2905 * CLIENTCREATESTRUCT.idFirstChild
2906 */
2907 { 0x0090, sent|optional },
2908 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2909 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2910 { WM_DESTROY, sent },
2911 { WM_NCDESTROY, sent },
2912 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2913 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2914 { 0 }
2915 };
2916 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2917 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2918 { HCBT_CREATEWND, hook },
2919 { WM_NCCREATE, sent },
2920 { WM_NCCALCSIZE, sent|wparam, 0 },
2921 { WM_CREATE, sent },
2922 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2923 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2924 { WM_MOVE, sent },
2925 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2926 { WM_GETMINMAXINFO, sent },
2927 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2928 { WM_NCCALCSIZE, sent|wparam, 1 },
2929 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2930 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2931 /* in MDI frame */
2932 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2933 { WM_NCCALCSIZE, sent|wparam, 1 },
2934 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2935 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2936 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2937 /* Win2k sends wparam set to
2938 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2939 * while Win9x doesn't bother to set child window id according to
2940 * CLIENTCREATESTRUCT.idFirstChild
2941 */
2942 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2943 { WM_SHOWWINDOW, sent|wparam, 1 },
2944 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2945 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2946 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2947 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2948 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2949 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2950 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2951
2952 /* Win9x: message sequence terminates here. */
2953
2954 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2955 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2956 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2957 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2958 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2959 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2960 { HCBT_SETFOCUS, hook|optional },
2961 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2962 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2963 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2964 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2965 { WM_SETFOCUS, sent|defwinproc|optional },
2966 { WM_MDIACTIVATE, sent|defwinproc|optional },
2967 /* in MDI frame */
2968 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2969 { WM_NCCALCSIZE, sent|wparam, 1 },
2970 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2971 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2972 { 0 }
2973 };
2974 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2975 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2976 /* restore the 1st MDI child */
2977 { WM_SETREDRAW, sent|wparam, 0 },
2978 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2979 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2980 { WM_NCCALCSIZE, sent|wparam, 1 },
2981 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2982 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2983 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2984 /* in MDI frame */
2985 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2986 { WM_NCCALCSIZE, sent|wparam, 1 },
2987 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2988 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2989 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2990 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2991 /* create the 2nd MDI child */
2992 { HCBT_CREATEWND, hook },
2993 { WM_NCCREATE, sent },
2994 { WM_NCCALCSIZE, sent|wparam, 0 },
2995 { WM_CREATE, sent },
2996 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2997 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2998 { WM_MOVE, sent },
2999 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3000 { WM_GETMINMAXINFO, sent },
3001 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3002 { WM_NCCALCSIZE, sent|wparam, 1 },
3003 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3004 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3005 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3006 /* in MDI frame */
3007 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3008 { WM_NCCALCSIZE, sent|wparam, 1 },
3009 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3010 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3011 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3012 /* Win2k sends wparam set to
3013 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3014 * while Win9x doesn't bother to set child window id according to
3015 * CLIENTCREATESTRUCT.idFirstChild
3016 */
3017 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3018 { WM_SHOWWINDOW, sent|wparam, 1 },
3019 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3020 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3021 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3022 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3023 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3024 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3025
3026 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3027 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3028
3029 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3030
3031 /* Win9x: message sequence terminates here. */
3032
3033 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3034 { HCBT_SETFOCUS, hook },
3035 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3036 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3037 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3038 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3039 { WM_SETFOCUS, sent }, /* in MDI client */
3040 { HCBT_SETFOCUS, hook },
3041 { WM_KILLFOCUS, sent }, /* in MDI client */
3042 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3043 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3044 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3045 { WM_SETFOCUS, sent|defwinproc },
3046
3047 { WM_MDIACTIVATE, sent|defwinproc },
3048 /* in MDI frame */
3049 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3050 { WM_NCCALCSIZE, sent|wparam, 1 },
3051 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3052 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3053 { 0 }
3054 };
3055 /* WM_MDICREATE MDI child window, initially visible and maximized */
3056 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3057 { WM_MDICREATE, sent },
3058 { HCBT_CREATEWND, hook },
3059 { WM_NCCREATE, sent },
3060 { WM_NCCALCSIZE, sent|wparam, 0 },
3061 { WM_CREATE, sent },
3062 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3063 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3064 { WM_MOVE, sent },
3065 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3066 { WM_GETMINMAXINFO, sent },
3067 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3068 { WM_NCCALCSIZE, sent|wparam, 1 },
3069 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3070 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3071
3072 /* in MDI frame */
3073 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3074 { WM_NCCALCSIZE, sent|wparam, 1 },
3075 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3076 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3077 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3078
3079 /* Win2k sends wparam set to
3080 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3081 * while Win9x doesn't bother to set child window id according to
3082 * CLIENTCREATESTRUCT.idFirstChild
3083 */
3084 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3085 { WM_SHOWWINDOW, sent|wparam, 1 },
3086 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3087
3088 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3089
3090 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3091 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3092 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3093
3094 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3095 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3096
3097 /* Win9x: message sequence terminates here. */
3098
3099 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3100 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3101 { HCBT_SETFOCUS, hook }, /* in MDI client */
3102 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3103 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3104 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3105 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3106 { HCBT_SETFOCUS, hook|optional },
3107 { WM_KILLFOCUS, sent }, /* in MDI client */
3108 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3109 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3110 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3111 { WM_SETFOCUS, sent|defwinproc },
3112
3113 { WM_MDIACTIVATE, sent|defwinproc },
3114
3115 /* in MDI child */
3116 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3117 { WM_NCCALCSIZE, sent|wparam, 1 },
3118 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3119 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3120
3121 /* in MDI frame */
3122 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3123 { WM_NCCALCSIZE, sent|wparam, 1 },
3124 { 0x0093, sent|defwinproc|optional },
3125 { 0x0093, sent|defwinproc|optional },
3126 { 0x0093, sent|defwinproc|optional },
3127 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3128 { WM_MOVE, sent|defwinproc },
3129 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3130
3131 /* in MDI client */
3132 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3133 { WM_NCCALCSIZE, sent|wparam, 1 },
3134 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3135 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3136
3137 /* in MDI child */
3138 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3139 { WM_NCCALCSIZE, sent|wparam, 1 },
3140 { 0x0093, sent|optional },
3141 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3142 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3143
3144 { 0x0093, sent|optional },
3145 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3146 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3147 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3148 { 0x0093, sent|defwinproc|optional },
3149 { 0x0093, sent|defwinproc|optional },
3150 { 0x0093, sent|defwinproc|optional },
3151 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3152 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3153
3154 { 0 }
3155 };
3156 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3157 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3158 { HCBT_CREATEWND, hook },
3159 { WM_GETMINMAXINFO, sent },
3160 { WM_NCCREATE, sent },
3161 { WM_NCCALCSIZE, sent|wparam, 0 },
3162 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3163 { WM_CREATE, sent },
3164 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3165 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3166 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3167 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3168 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3169 { WM_MOVE, sent },
3170 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3171 { WM_GETMINMAXINFO, sent },
3172 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3173 { WM_GETMINMAXINFO, sent|defwinproc },
3174 { WM_NCCALCSIZE, sent|wparam, 1 },
3175 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3176 { WM_MOVE, sent|defwinproc },
3177 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3178 /* in MDI frame */
3179 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3180 { WM_NCCALCSIZE, sent|wparam, 1 },
3181 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3182 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3183 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3184 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3185 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3186 /* Win2k sends wparam set to
3187 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3188 * while Win9x doesn't bother to set child window id according to
3189 * CLIENTCREATESTRUCT.idFirstChild
3190 */
3191 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3192 { 0 }
3193 };
3194 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3195 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3196 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3197 { HCBT_SYSCOMMAND, hook },
3198 { WM_CLOSE, sent|defwinproc },
3199 { WM_MDIDESTROY, sent }, /* in MDI client */
3200
3201 /* bring the 1st MDI child to top */
3202 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3203 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3204
3205 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3206
3207 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3208 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3209 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3210
3211 /* maximize the 1st MDI child */
3212 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3213 { WM_GETMINMAXINFO, sent|defwinproc },
3214 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3215 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3216 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3217 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3218 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3219
3220 /* restore the 2nd MDI child */
3221 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3222 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3223 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3224 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3225
3226 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3227
3228 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3229 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3230
3231 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3232
3233 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3234 /* in MDI frame */
3235 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3236 { WM_NCCALCSIZE, sent|wparam, 1 },
3237 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3238 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3239 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3240
3241 /* bring the 1st MDI child to top */
3242 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3243 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3244 { HCBT_SETFOCUS, hook },
3245 { WM_KILLFOCUS, sent|defwinproc },
3246 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3247 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3248 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3249 { WM_SETFOCUS, sent }, /* in MDI client */
3250 { HCBT_SETFOCUS, hook },
3251 { WM_KILLFOCUS, sent }, /* in MDI client */
3252 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3253 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3254 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3255 { WM_SETFOCUS, sent|defwinproc },
3256 { WM_MDIACTIVATE, sent|defwinproc },
3257 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3258
3259 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3260 { WM_SHOWWINDOW, sent|wparam, 1 },
3261 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3262 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3263 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3264 { WM_MDIREFRESHMENU, sent },
3265
3266 { HCBT_DESTROYWND, hook },
3267 /* Win2k sends wparam set to
3268 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3269 * while Win9x doesn't bother to set child window id according to
3270 * CLIENTCREATESTRUCT.idFirstChild
3271 */
3272 { 0x0090, sent|defwinproc|optional },
3273 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3274 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3275 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3276 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3277 { WM_ERASEBKGND, sent|parent|optional },
3278 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3279
3280 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3281 { WM_DESTROY, sent|defwinproc },
3282 { WM_NCDESTROY, sent|defwinproc },
3283 { 0 }
3284 };
3285 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3286 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3287 { WM_MDIDESTROY, sent }, /* in MDI client */
3288 { WM_SHOWWINDOW, sent|wparam, 0 },
3289 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3290 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3291 { WM_ERASEBKGND, sent|parent|optional },
3292 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3293
3294 { HCBT_SETFOCUS, hook },
3295 { WM_KILLFOCUS, sent },
3296 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3297 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3298 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3299 { WM_SETFOCUS, sent }, /* in MDI client */
3300 { HCBT_SETFOCUS, hook },
3301 { WM_KILLFOCUS, sent }, /* in MDI client */
3302 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3303 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3304 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3305 { WM_SETFOCUS, sent },
3306
3307 /* in MDI child */
3308 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3309 { WM_NCCALCSIZE, sent|wparam, 1 },
3310 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3311 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3312
3313 /* in MDI frame */
3314 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3315 { WM_NCCALCSIZE, sent|wparam, 1 },
3316 { 0x0093, sent|defwinproc|optional },
3317 { 0x0093, sent|defwinproc|optional },
3318 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3319 { WM_MOVE, sent|defwinproc },
3320 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3321
3322 /* in MDI client */
3323 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3324 { WM_NCCALCSIZE, sent|wparam, 1 },
3325 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3326 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3327
3328 /* in MDI child */
3329 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3330 { WM_NCCALCSIZE, sent|wparam, 1 },
3331 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3332 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3333
3334 /* in MDI child */
3335 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3336 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3337 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3338 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3339
3340 /* in MDI frame */
3341 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3342 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3343 { 0x0093, sent|defwinproc|optional },
3344 { 0x0093, sent|defwinproc|optional },
3345 { 0x0093, sent|defwinproc|optional },
3346 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3347 { WM_MOVE, sent|defwinproc },
3348 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3349
3350 /* in MDI client */
3351 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3352 { WM_NCCALCSIZE, sent|wparam, 1 },
3353 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3354 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3355
3356 /* in MDI child */
3357 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3358 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3359 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3360 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3361 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3362 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3363
3364 { 0x0093, sent|defwinproc|optional },
3365 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3366 { 0x0093, sent|defwinproc|optional },
3367 { 0x0093, sent|defwinproc|optional },
3368 { 0x0093, sent|defwinproc|optional },
3369 { 0x0093, sent|optional },
3370
3371 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3372 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3373 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3374 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3375 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3376
3377 /* in MDI frame */
3378 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3379 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3380 { 0x0093, sent|defwinproc|optional },
3381 { 0x0093, sent|defwinproc|optional },
3382 { 0x0093, sent|defwinproc|optional },
3383 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3384 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3385 { 0x0093, sent|optional },
3386
3387 { WM_NCACTIVATE, sent|wparam, 0 },
3388 { WM_MDIACTIVATE, sent },
3389
3390 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3391 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3392 { WM_NCCALCSIZE, sent|wparam, 1 },
3393
3394 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3395
3396 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3397 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3398 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3399
3400 /* in MDI child */
3401 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3402 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3403 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3404 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3405
3406 /* in MDI frame */
3407 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3408 { WM_NCCALCSIZE, sent|wparam, 1 },
3409 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3410 { WM_MOVE, sent|defwinproc },
3411 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3412
3413 /* in MDI client */
3414 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3415 { WM_NCCALCSIZE, sent|wparam, 1 },
3416 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3417 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3418 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3419 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3420 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3421 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3422 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3423
3424 { HCBT_SETFOCUS, hook },
3425 { WM_KILLFOCUS, sent },
3426 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3427 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3428 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3429 { WM_SETFOCUS, sent }, /* in MDI client */
3430
3431 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3432
3433 { HCBT_DESTROYWND, hook },
3434 /* Win2k sends wparam set to
3435 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3436 * while Win9x doesn't bother to set child window id according to
3437 * CLIENTCREATESTRUCT.idFirstChild
3438 */
3439 { 0x0090, sent|optional },
3440 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3441
3442 { WM_SHOWWINDOW, sent|wparam, 0 },
3443 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3444 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3445 { WM_ERASEBKGND, sent|parent|optional },
3446 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3447
3448 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3449 { WM_DESTROY, sent },
3450 { WM_NCDESTROY, sent },
3451 { 0 }
3452 };
3453 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3454 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3455 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3456 { WM_GETMINMAXINFO, sent },
3457 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3458 { WM_NCCALCSIZE, sent|wparam, 1 },
3459 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3460 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3461
3462 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3463 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3464 { HCBT_SETFOCUS, hook|optional },
3465 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3466 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3467 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3468 { HCBT_SETFOCUS, hook|optional },
3469 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3470 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3471 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3472 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3473 { WM_SETFOCUS, sent|optional|defwinproc },
3474 { WM_MDIACTIVATE, sent|optional|defwinproc },
3475 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3476 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3477 /* in MDI frame */
3478 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3479 { WM_NCCALCSIZE, sent|wparam, 1 },
3480 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3481 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3482 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3483 { 0 }
3484 };
3485 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3486 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3487 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3488 { WM_GETMINMAXINFO, sent },
3489 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3490 { WM_GETMINMAXINFO, sent|defwinproc },
3491 { WM_NCCALCSIZE, sent|wparam, 1 },
3492 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3493 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3494
3495 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3496 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3497 { HCBT_SETFOCUS, hook|optional },
3498 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3499 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3500 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3501 { HCBT_SETFOCUS, hook|optional },
3502 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3503 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3504 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3505 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3506 { WM_SETFOCUS, sent|defwinproc|optional },
3507 { WM_MDIACTIVATE, sent|defwinproc|optional },
3508 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3509 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3510 { 0 }
3511 };
3512 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3513 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3514 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3515 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3516 { WM_GETMINMAXINFO, sent },
3517 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3518 { WM_GETMINMAXINFO, sent|defwinproc },
3519 { WM_NCCALCSIZE, sent|wparam, 1 },
3520 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3521 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3522 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3523 { WM_MOVE, sent|defwinproc },
3524 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3525
3526 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3527 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3528 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3529 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3530 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3531 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3532 /* in MDI frame */
3533 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3534 { WM_NCCALCSIZE, sent|wparam, 1 },
3535 { 0x0093, sent|defwinproc|optional },
3536 { 0x0094, sent|defwinproc|optional },
3537 { 0x0094, sent|defwinproc|optional },
3538 { 0x0094, sent|defwinproc|optional },
3539 { 0x0094, sent|defwinproc|optional },
3540 { 0x0093, sent|defwinproc|optional },
3541 { 0x0093, sent|defwinproc|optional },
3542 { 0x0091, sent|defwinproc|optional },
3543 { 0x0092, sent|defwinproc|optional },
3544 { 0x0092, sent|defwinproc|optional },
3545 { 0x0092, sent|defwinproc|optional },
3546 { 0x0092, sent|defwinproc|optional },
3547 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3548 { WM_MOVE, sent|defwinproc },
3549 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3550 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3551 /* in MDI client */
3552 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3553 { WM_NCCALCSIZE, sent|wparam, 1 },
3554 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3555 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3556 /* in MDI child */
3557 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3558 { WM_GETMINMAXINFO, sent|defwinproc },
3559 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3560 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3561 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3562 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3563 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3564 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3565 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3566 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3567 /* in MDI frame */
3568 { 0x0093, sent|optional },
3569 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3570 { 0x0093, sent|defwinproc|optional },
3571 { 0x0093, sent|defwinproc|optional },
3572 { 0x0093, sent|defwinproc|optional },
3573 { 0x0091, sent|defwinproc|optional },
3574 { 0x0092, sent|defwinproc|optional },
3575 { 0x0092, sent|defwinproc|optional },
3576 { 0x0092, sent|defwinproc|optional },
3577 { 0x0092, sent|defwinproc|optional },
3578 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3579 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3580 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3581 { 0 }
3582 };
3583 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3584 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3585 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3586 { WM_GETMINMAXINFO, sent },
3587 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3588 { WM_NCCALCSIZE, sent|wparam, 1 },
3589 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3590 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3591 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3592 /* in MDI frame */
3593 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3594 { WM_NCCALCSIZE, sent|wparam, 1 },
3595 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3596 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3597 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3598 { 0 }
3599 };
3600 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3601 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3602 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3603 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3604 { WM_NCCALCSIZE, sent|wparam, 1 },
3605 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3606 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3607 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3608 /* in MDI frame */
3609 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3610 { WM_NCCALCSIZE, sent|wparam, 1 },
3611 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3612 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3613 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3614 { 0 }
3615 };
3616 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3617 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3618 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3619 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3620 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3621 { WM_NCCALCSIZE, sent|wparam, 1 },
3622 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3623 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3624 { WM_MOVE, sent|defwinproc },
3625 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3626 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3627 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3628 { HCBT_SETFOCUS, hook },
3629 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3630 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3631 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3632 { WM_SETFOCUS, sent },
3633 { 0 }
3634 };
3635 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3636 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3637 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3638 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3639 { WM_NCCALCSIZE, sent|wparam, 1 },
3640 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3641 { WM_MOVE, sent|defwinproc },
3642 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3643 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3644 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3645 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3646 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3647 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3648 { 0 }
3649 };
3650 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3651 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3652 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3653 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3654 { WM_NCCALCSIZE, sent|wparam, 1 },
3655 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3656 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3657 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3658 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3659 /* in MDI frame */
3660 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3661 { WM_NCCALCSIZE, sent|wparam, 1 },
3662 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3663 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3664 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3665 { 0 }
3666 };
3667
3668 static HWND mdi_client;
3669 static WNDPROC old_mdi_client_proc;
3670
3671 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3672 {
3673 struct recvd_message msg;
3674
3675 /* do not log painting messages */
3676 if (message != WM_PAINT &&
3677 message != WM_NCPAINT &&
3678 message != WM_SYNCPAINT &&
3679 message != WM_ERASEBKGND &&
3680 message != WM_NCHITTEST &&
3681 message != WM_GETTEXT &&
3682 message != WM_MDIGETACTIVE &&
3683 !ignore_message( message ))
3684 {
3685 msg.hwnd = hwnd;
3686 msg.message = message;
3687 msg.flags = sent|wparam|lparam;
3688 msg.wParam = wParam;
3689 msg.lParam = lParam;
3690 msg.descr = "mdi client";
3691 add_message(&msg);
3692 }
3693
3694 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3695 }
3696
3697 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3698 {
3699 static LONG defwndproc_counter = 0;
3700 LRESULT ret;
3701 struct recvd_message msg;
3702
3703 /* do not log painting messages */
3704 if (message != WM_PAINT &&
3705 message != WM_NCPAINT &&
3706 message != WM_SYNCPAINT &&
3707 message != WM_ERASEBKGND &&
3708 message != WM_NCHITTEST &&
3709 message != WM_GETTEXT &&
3710 !ignore_message( message ))
3711 {
3712 switch (message)
3713 {
3714 case WM_MDIACTIVATE:
3715 {
3716 HWND active, client = GetParent(hwnd);
3717
3718 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3719
3720 if (hwnd == (HWND)lParam) /* if we are being activated */
3721 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3722 else
3723 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3724 break;
3725 }
3726 }
3727
3728 msg.hwnd = hwnd;
3729 msg.message = message;
3730 msg.flags = sent|wparam|lparam;
3731 if (defwndproc_counter) msg.flags |= defwinproc;
3732 msg.wParam = wParam;
3733 msg.lParam = lParam;
3734 msg.descr = "mdi child";
3735 add_message(&msg);
3736 }
3737
3738 defwndproc_counter++;
3739 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3740 defwndproc_counter--;
3741
3742 return ret;
3743 }
3744
3745 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3746 {
3747 static LONG defwndproc_counter = 0;
3748 LRESULT ret;
3749 struct recvd_message msg;
3750
3751 /* do not log painting messages */
3752 if (message != WM_PAINT &&
3753 message != WM_NCPAINT &&
3754 message != WM_SYNCPAINT &&
3755 message != WM_ERASEBKGND &&
3756 message != WM_NCHITTEST &&
3757 message != WM_GETTEXT &&
3758 !ignore_message( message ))
3759 {
3760 msg.hwnd = hwnd;
3761 msg.message = message;
3762 msg.flags = sent|wparam|lparam;
3763 if (defwndproc_counter) msg.flags |= defwinproc;
3764 msg.wParam = wParam;
3765 msg.lParam = lParam;
3766 msg.descr = "mdi frame";
3767 add_message(&msg);
3768 }
3769
3770 defwndproc_counter++;
3771 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3772 defwndproc_counter--;
3773
3774 return ret;
3775 }
3776
3777 static BOOL mdi_RegisterWindowClasses(void)
3778 {
3779 WNDCLASSA cls;
3780
3781 cls.style = 0;
3782 cls.lpfnWndProc = mdi_frame_wnd_proc;
3783 cls.cbClsExtra = 0;
3784 cls.cbWndExtra = 0;
3785 cls.hInstance = GetModuleHandleA(0);
3786 cls.hIcon = 0;
3787 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3788 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3789 cls.lpszMenuName = NULL;
3790 cls.lpszClassName = "MDI_frame_class";
3791 if (!RegisterClassA(&cls)) return FALSE;
3792
3793 cls.lpfnWndProc = mdi_child_wnd_proc;
3794 cls.lpszClassName = "MDI_child_class";
3795 if (!RegisterClassA(&cls)) return FALSE;
3796
3797 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3798 old_mdi_client_proc = cls.lpfnWndProc;
3799 cls.hInstance = GetModuleHandleA(0);
3800 cls.lpfnWndProc = mdi_client_hook_proc;
3801 cls.lpszClassName = "MDI_client_class";
3802 if (!RegisterClassA(&cls)) assert(0);
3803
3804 return TRUE;
3805 }
3806
3807 static void test_mdi_messages(void)
3808 {
3809 MDICREATESTRUCTA mdi_cs;
3810 CLIENTCREATESTRUCT client_cs;
3811 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3812 BOOL zoomed;
3813 RECT rc;
3814 HMENU hMenu = CreateMenu();
3815 LONG val;
3816
3817 if (!mdi_RegisterWindowClasses()) assert(0);
3818
3819 flush_sequence();
3820
3821 trace("creating MDI frame window\n");
3822 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3823 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3824 WS_MAXIMIZEBOX | WS_VISIBLE,
3825 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3826 GetDesktopWindow(), hMenu,
3827 GetModuleHandleA(0), NULL);
3828 assert(mdi_frame);
3829 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3830
3831 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3832 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3833
3834 trace("creating MDI client window\n");
3835 GetClientRect(mdi_frame, &rc);
3836 client_cs.hWindowMenu = 0;
3837 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3838 mdi_client = CreateWindowExA(0, "MDI_client_class",
3839 NULL,
3840 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3841 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3842 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3843 assert(mdi_client);
3844 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3845
3846 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3847 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3848 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3849
3850 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3851 ok(!active_child, "wrong active MDI child %p\n", active_child);
3852 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3853
3854 SetFocus(0);
3855 flush_sequence();
3856
3857 trace("creating invisible MDI child window\n");
3858 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3859 WS_CHILD,
3860 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3861 mdi_client, 0, GetModuleHandleA(0), NULL);
3862 assert(mdi_child);
3863
3864 flush_sequence();
3865 ShowWindow(mdi_child, SW_SHOWNORMAL);
3866 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3867
3868 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3869 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3870
3871 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3872 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3873
3874 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3875 ok(!active_child, "wrong active MDI child %p\n", active_child);
3876 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3877
3878 ShowWindow(mdi_child, SW_HIDE);
3879 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3880 flush_sequence();
3881
3882 ShowWindow(mdi_child, SW_SHOW);
3883 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3884
3885 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3886 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3887
3888 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3889 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3890
3891 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3892 ok(!active_child, "wrong active MDI child %p\n", active_child);
3893 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3894
3895 DestroyWindow(mdi_child);
3896 flush_sequence();
3897
3898 trace("creating visible MDI child window\n");
3899 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3900 WS_CHILD | WS_VISIBLE,
3901 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3902 mdi_client, 0, GetModuleHandleA(0), NULL);
3903 assert(mdi_child);
3904 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3905
3906 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3907 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3908
3909 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3910 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3911
3912 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3913 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3914 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3915 flush_sequence();
3916
3917 DestroyWindow(mdi_child);
3918 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3919
3920 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3921 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3922
3923 /* Win2k: MDI client still returns a just destroyed child as active
3924 * Win9x: MDI client returns 0
3925 */
3926 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3927 ok(active_child == mdi_child || /* win2k */
3928 !active_child, /* win9x */
3929 "wrong active MDI child %p\n", active_child);
3930 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3931
3932 flush_sequence();
3933
3934 trace("creating invisible MDI child window\n");
3935 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3936 WS_CHILD,
3937 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3938 mdi_client, 0, GetModuleHandleA(0), NULL);
3939 assert(mdi_child2);
3940 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3941
3942 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3943 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3944
3945 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3946 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3947
3948 /* Win2k: MDI client still returns a just destroyed child as active
3949 * Win9x: MDI client returns mdi_child2
3950 */
3951 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3952 ok(active_child == mdi_child || /* win2k */
3953 active_child == mdi_child2, /* win9x */
3954 "wrong active MDI child %p\n", active_child);
3955 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3956 flush_sequence();
3957
3958 ShowWindow(mdi_child2, SW_MAXIMIZE);
3959 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3960
3961 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3962 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3963
3964 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3965 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3966 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3967 flush_sequence();
3968
3969 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3970 ok(GetFocus() == mdi_child2 || /* win2k */
3971 GetFocus() == 0, /* win9x */
3972 "wrong focus window %p\n", GetFocus());
3973
3974 SetFocus(0);
3975 flush_sequence();
3976
3977 ShowWindow(mdi_child2, SW_HIDE);
3978 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3979
3980 ShowWindow(mdi_child2, SW_RESTORE);
3981 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3982 flush_sequence();
3983
3984 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3985 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3986
3987 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3988 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3989 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3990 flush_sequence();
3991
3992 SetFocus(0);
3993 flush_sequence();
3994
3995 ShowWindow(mdi_child2, SW_HIDE);
3996 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3997
3998 ShowWindow(mdi_child2, SW_SHOW);
3999 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
4000
4001 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4002 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4003
4004 ShowWindow(mdi_child2, SW_MAXIMIZE);
4005 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
4006
4007 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4008 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4009
4010 ShowWindow(mdi_child2, SW_RESTORE);
4011 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4012
4013 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4014 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4015
4016 ShowWindow(mdi_child2, SW_MINIMIZE);
4017 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
4018
4019 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4020 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4021
4022 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4023 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4024 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4025 flush_sequence();
4026
4027 ShowWindow(mdi_child2, SW_RESTORE);
4028 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4029
4030 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4031 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4032
4033 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4034 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4035 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4036 flush_sequence();
4037
4038 SetFocus(0);
4039 flush_sequence();
4040
4041 ShowWindow(mdi_child2, SW_HIDE);
4042 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4043
4044 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4045 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4046
4047 DestroyWindow(mdi_child2);
4048 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4049
4050 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4051 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4052
4053 trace("Testing WM_CHILDACTIVATE\n");
4054
4055 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4056 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4057 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4058 mdi_client, 0, GetModuleHandleA(0), NULL);
4059
4060 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4061 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4062 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4063 mdi_client, 0, GetModuleHandleA(0), NULL);
4064
4065 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4066 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4067 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4068
4069 flush_sequence();
4070 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4071 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4072
4073 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4074 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4075 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4076 flush_sequence();
4077
4078 EnableWindow(mdi_child, TRUE);
4079
4080 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4081 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4082 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4083
4084 flush_sequence();
4085 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4086 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4087
4088 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4089 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4090 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4091 flush_sequence();
4092
4093 DestroyWindow(mdi_child);
4094 DestroyWindow(mdi_child2);
4095 flush_sequence();
4096
4097 /* test for maximized MDI children */
4098 trace("creating maximized visible MDI child window 1\n");
4099 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4100 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4101 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4102 mdi_client, 0, GetModuleHandleA(0), NULL);
4103 assert(mdi_child);
4104 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4105 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4106
4107 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4108 ok(GetFocus() == mdi_child || /* win2k */
4109 GetFocus() == 0, /* win9x */
4110 "wrong focus window %p\n", GetFocus());
4111
4112 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4113 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4114 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4115 flush_sequence();
4116
4117 trace("creating maximized visible MDI child window 2\n");
4118 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4119 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4120 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4121 mdi_client, 0, GetModuleHandleA(0), NULL);
4122 assert(mdi_child2);
4123 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4124 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4125 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4126
4127 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4128 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4129
4130 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4131 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4132 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4133 flush_sequence();
4134
4135 trace("destroying maximized visible MDI child window 2\n");
4136 DestroyWindow(mdi_child2);
4137 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4138
4139 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4140
4141 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4142 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4143
4144 /* Win2k: MDI client still returns a just destroyed child as active
4145 * Win9x: MDI client returns 0
4146 */
4147 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4148 ok(active_child == mdi_child2 || /* win2k */
4149 !active_child, /* win9x */
4150 "wrong active MDI child %p\n", active_child);
4151 flush_sequence();
4152
4153 ShowWindow(mdi_child, SW_MAXIMIZE);
4154 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4155 flush_sequence();
4156
4157 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4158 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4159
4160 trace("re-creating maximized visible MDI child window 2\n");
4161 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4162 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4163 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4164 mdi_client, 0, GetModuleHandleA(0), NULL);
4165 assert(mdi_child2);
4166 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4167 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4168 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4169
4170 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4171 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4172
4173 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4174 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4175 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4176 flush_sequence();
4177
4178 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4179 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4180 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4181
4182 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4183 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4184 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4185
4186 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4187 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4188 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4189 flush_sequence();
4190
4191 DestroyWindow(mdi_child);
4192 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4193
4194 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4195 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4196
4197 /* Win2k: MDI client still returns a just destroyed child as active
4198 * Win9x: MDI client returns 0
4199 */
4200 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4201 ok(active_child == mdi_child || /* win2k */
4202 !active_child, /* win9x */
4203 "wrong active MDI child %p\n", active_child);
4204 flush_sequence();
4205
4206 trace("creating maximized invisible MDI child window\n");
4207 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4208 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4209 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4210 mdi_client, 0, GetModuleHandleA(0), NULL);
4211 assert(mdi_child2);
4212 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4213 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4214 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4215 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4216
4217 /* Win2k: MDI client still returns a just destroyed child as active
4218 * Win9x: MDI client returns 0
4219 */
4220 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4221 ok(active_child == mdi_child || /* win2k */
4222 !active_child || active_child == mdi_child2, /* win9x */
4223 "wrong active MDI child %p\n", active_child);
4224 flush_sequence();
4225
4226 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4227 ShowWindow(mdi_child2, SW_MAXIMIZE);
4228 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4229 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4230 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4231 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4232
4233 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4234 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4235 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4236 flush_sequence();
4237
4238 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4239 flush_sequence();
4240
4241 /* end of test for maximized MDI children */
4242 SetFocus(0);
4243 flush_sequence();
4244 trace("creating maximized visible MDI child window 1(Switch test)\n");
4245 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4246 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4247 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4248 mdi_client, 0, GetModuleHandleA(0), NULL);
4249 assert(mdi_child);
4250 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4251 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4252
4253 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4254 ok(GetFocus() == mdi_child || /* win2k */
4255 GetFocus() == 0, /* win9x */
4256 "wrong focus window %p(Switch test)\n", GetFocus());
4257
4258 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4259 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4260 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4261 flush_sequence();
4262
4263 trace("creating maximized visible MDI child window 2(Switch test)\n");
4264 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4265 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4266 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4267 mdi_client, 0, GetModuleHandleA(0), NULL);
4268 assert(mdi_child2);
4269 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4270
4271 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4272 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4273
4274 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4275 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4276
4277 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4278 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4279 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4280 flush_sequence();
4281
4282 trace("Switch child window.\n");
4283 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4284 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4285 trace("end of test for switch maximized MDI children\n");
4286 flush_sequence();
4287
4288 /* Prepare for switching test of not maximized MDI children */
4289 ShowWindow( mdi_child, SW_NORMAL );
4290 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4291 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4292 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4293 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4294 flush_sequence();
4295
4296 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4297 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4298 trace("end of test for switch not maximized MDI children\n");
4299 flush_sequence();
4300
4301 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4302 flush_sequence();
4303
4304 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4305 flush_sequence();
4306
4307 SetFocus(0);
4308 flush_sequence();
4309 /* end of tests for switch maximized/not maximized MDI children */
4310
4311 mdi_cs.szClass = "MDI_child_Class";
4312 mdi_cs.szTitle = "MDI child";
4313 mdi_cs.hOwner = GetModuleHandleA(0);
4314 mdi_cs.x = 0;
4315 mdi_cs.y = 0;
4316 mdi_cs.cx = CW_USEDEFAULT;
4317 mdi_cs.cy = CW_USEDEFAULT;
4318 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4319 mdi_cs.lParam = 0;
4320 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4321 ok(mdi_child != 0, "MDI child creation failed\n");
4322 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4323
4324 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4325
4326 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4327 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4328
4329 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4330 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4331 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4332
4333 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4334 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4335 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4336 flush_sequence();
4337
4338 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4339 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4340
4341 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4342 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4343 ok(!active_child, "wrong active MDI child %p\n", active_child);
4344
4345 SetFocus(0);
4346 flush_sequence();
4347
4348 val = GetWindowLongA(mdi_client, 0);
4349 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4350 DestroyWindow(mdi_client);
4351 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4352
4353 /* test maximization of MDI child with invisible parent */
4354 client_cs.hWindowMenu = 0;
4355 mdi_client = CreateWindowA("MDI_client_class",
4356 NULL,
4357 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4358 0, 0, 660, 430,
4359 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4360 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4361
4362 ShowWindow(mdi_client, SW_HIDE);
4363 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4364
4365 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4366 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4367 0, 0, 650, 440,
4368 mdi_client, 0, GetModuleHandleA(0), NULL);
4369 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4370
4371 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4372 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4373 zoomed = IsZoomed(mdi_child);
4374 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4375
4376 ShowWindow(mdi_client, SW_SHOW);
4377 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4378
4379 DestroyWindow(mdi_child);
4380 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4381
4382 /* end of test for maximization of MDI child with invisible parent */
4383
4384 DestroyWindow(mdi_client);
4385 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4386
4387 DestroyWindow(mdi_frame);
4388 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4389 }
4390 /************************* End of MDI test **********************************/
4391
4392 static void test_WM_SETREDRAW(HWND hwnd)
4393 {
4394 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4395
4396 flush_events();
4397 flush_sequence();
4398
4399 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4400 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4401
4402 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4403 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4404
4405 flush_sequence();
4406 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4407 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4408
4409 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4410 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4411
4412 /* restore original WS_VISIBLE state */
4413 SetWindowLongA(hwnd, GWL_STYLE, style);
4414
4415 flush_events();
4416 flush_sequence();
4417 }
4418
4419 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4420 {
4421 struct recvd_message msg;
4422
4423 if (ignore_message( message )) return 0;
4424
4425 switch (message)
4426 {
4427 /* ignore */
4428 case WM_MOUSEMOVE:
4429 case WM_NCMOUSEMOVE:
4430 case WM_NCMOUSELEAVE:
4431 case WM_SETCURSOR:
4432 return 0;
4433 case WM_NCHITTEST:
4434 return HTCLIENT;
4435 }
4436
4437 msg.hwnd = hwnd;
4438 msg.message = message;
4439 msg.flags = sent|wparam|lparam;
4440 msg.wParam = wParam;
4441 msg.lParam = lParam;
4442 msg.descr = "dialog";
4443 add_message(&msg);
4444
4445 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4446 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4447 return 0;
4448 }
4449
4450 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4451 {
4452 struct recvd_message msg;
4453
4454 if (ignore_message( message )) return 0;
4455
4456 switch (message)
4457 {
4458 /* ignore */
4459 case WM_MOUSEMOVE:
4460 case WM_NCMOUSEMOVE:
4461 case WM_NCMOUSELEAVE:
4462 case WM_SETCURSOR:
4463 return 0;
4464 case WM_NCHITTEST:
4465 return HTCLIENT;
4466 }
4467
4468 msg.hwnd = hwnd;
4469 msg.message = message;
4470 msg.flags = sent|wparam|lparam;
4471 msg.wParam = wParam;
4472 msg.lParam = lParam;
4473 msg.descr = "dialog";
4474 add_message(&msg);
4475
4476 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4477 return 0;
4478 }
4479
4480 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4481 {
4482 DWORD style, exstyle;
4483 INT xmin, xmax;
4484 BOOL ret;
4485
4486 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4487 style = GetWindowLongA(hwnd, GWL_STYLE);
4488 /* do not be confused by WS_DLGFRAME set */
4489 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4490
4491 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4492 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4493
4494 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4495 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4496 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4497 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4498 else
4499 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4500
4501 style = GetWindowLongA(hwnd, GWL_STYLE);
4502 if (set) ok(style & set, "style %08x should be set\n", set);
4503 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4504
4505 /* a subsequent call should do nothing */
4506 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4507 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4508 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4509
4510 xmin = 0xdeadbeef;
4511 xmax = 0xdeadbeef;
4512 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4513 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4514 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4515 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4516 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4517 }
4518
4519 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4520 {
4521 DWORD style, exstyle;
4522 SCROLLINFO si;
4523 BOOL ret;
4524
4525 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4526 style = GetWindowLongA(hwnd, GWL_STYLE);
4527 /* do not be confused by WS_DLGFRAME set */
4528 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4529
4530 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4531 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4532
4533 si.cbSize = sizeof(si);
4534 si.fMask = SIF_RANGE;
4535 si.nMin = min;
4536 si.nMax = max;
4537 SetScrollInfo(hwnd, ctl, &si, TRUE);
4538 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4539 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4540 else
4541 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4542
4543 style = GetWindowLongA(hwnd, GWL_STYLE);
4544 if (set) ok(style & set, "style %08x should be set\n", set);
4545 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4546
4547 /* a subsequent call should do nothing */
4548 SetScrollInfo(hwnd, ctl, &si, TRUE);
4549 if (style & WS_HSCROLL)
4550 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4551 else if (style & WS_VSCROLL)
4552 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4553 else
4554 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4555
4556 si.fMask = SIF_PAGE;
4557 si.nPage = 5;
4558 SetScrollInfo(hwnd, ctl, &si, FALSE);
4559 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4560
4561 si.fMask = SIF_POS;
4562 si.nPos = max - 1;
4563 SetScrollInfo(hwnd, ctl, &si, FALSE);
4564 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4565
4566 si.fMask = SIF_RANGE;
4567 si.nMin = 0xdeadbeef;
4568 si.nMax = 0xdeadbeef;
4569 ret = GetScrollInfo(hwnd, ctl, &si);
4570 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4571 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4572 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4573 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4574 }
4575
4576 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4577 static void test_scroll_messages(HWND hwnd)
4578 {
4579 SCROLLINFO si;
4580 INT min, max;
4581 BOOL ret;
4582
4583 flush_events();
4584 flush_sequence();
4585
4586 min = 0xdeadbeef;
4587 max = 0xdeadbeef;
4588 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4589 ok( ret, "GetScrollRange error %d\n", GetLastError());
4590 if (sequence->message != WmGetScrollRangeSeq[0].message)
4591 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4592 /* values of min and max are undefined */
4593 flush_sequence();
4594
4595 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4596 ok( ret, "SetScrollRange error %d\n", GetLastError());
4597 if (sequence->message != WmSetScrollRangeSeq[0].message)
4598 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4599 flush_sequence();
4600
4601 min = 0xdeadbeef;
4602 max = 0xdeadbeef;
4603 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4604 ok( ret, "GetScrollRange error %d\n", GetLastError());
4605 if (sequence->message != WmGetScrollRangeSeq[0].message)
4606 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4607 /* values of min and max are undefined */
4608 flush_sequence();
4609
4610 si.cbSize = sizeof(si);
4611 si.fMask = SIF_RANGE;
4612 si.nMin = 20;
4613 si.nMax = 160;
4614 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4615 if (sequence->message != WmSetScrollRangeSeq[0].message)
4616 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4617 flush_sequence();
4618
4619 si.fMask = SIF_PAGE;
4620 si.nPage = 10;
4621 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4622 if (sequence->message != WmSetScrollRangeSeq[0].message)
4623 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4624 flush_sequence();
4625
4626 si.fMask = SIF_POS;
4627 si.nPos = 20;
4628 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4629 if (sequence->message != WmSetScrollRangeSeq[0].message)
4630 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4631 flush_sequence();
4632
4633 si.fMask = SIF_RANGE;
4634 si.nMin = 0xdeadbeef;
4635 si.nMax = 0xdeadbeef;
4636 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4637 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4638 if (sequence->message != WmGetScrollInfoSeq[0].message)
4639 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4640 /* values of min and max are undefined */
4641 flush_sequence();
4642
4643 /* set WS_HSCROLL */
4644 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4645 /* clear WS_HSCROLL */
4646 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4647
4648 /* set WS_HSCROLL */
4649 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4650 /* clear WS_HSCROLL */
4651 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4652
4653 /* set WS_VSCROLL */
4654 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4655 /* clear WS_VSCROLL */
4656 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4657
4658 /* set WS_VSCROLL */
4659 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4660 /* clear WS_VSCROLL */
4661 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4662 }
4663
4664 static void test_showwindow(void)
4665 {
4666 HWND hwnd, hchild;
4667 RECT rc;
4668
4669 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4670 100, 100, 200, 200, 0, 0, 0, NULL);
4671 ok (hwnd != 0, "Failed to create overlapped window\n");
4672 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4673 0, 0, 10, 10, hwnd, 0, 0, NULL);
4674 ok (hchild != 0, "Failed to create child\n");
4675 flush_sequence();
4676
4677 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4678 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4679 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4680 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4681
4682 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4683 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4684 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4685 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4686 /* back to invisible */
4687 ShowWindow(hchild, SW_HIDE);
4688 ShowWindow(hwnd, SW_HIDE);
4689 flush_sequence();
4690 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4691 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4692 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4693 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4694 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4695 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4696 flush_sequence();
4697 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4698 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4699 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4700 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4701 ShowWindow( hwnd, SW_SHOW);
4702 flush_sequence();
4703 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4704 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4705 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4706
4707 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4708 ShowWindow( hchild, SW_HIDE);
4709 flush_sequence();
4710 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4711 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4712 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4713
4714 SetCapture(hchild);
4715 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4716 DestroyWindow(hchild);
4717 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4718
4719 DestroyWindow(hwnd);
4720 flush_sequence();
4721
4722 /* Popup windows */
4723 /* Test 1:
4724 * 1. Create invisible maximized popup window.
4725 * 2. Move and resize it.
4726 * 3. Show it maximized.
4727 */
4728 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4729 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4730 100, 100, 200, 200, 0, 0, 0, NULL);
4731 ok (hwnd != 0, "Failed to create popup window\n");
4732 ok(IsZoomed(hwnd), "window should be maximized\n");
4733 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4734
4735 GetWindowRect(hwnd, &rc);
4736 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4737 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4738 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4739 /* Reset window's size & position */
4740 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4741 ok(IsZoomed(hwnd), "window should be maximized\n");
4742 flush_sequence();
4743
4744 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4745 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4746 ok(IsZoomed(hwnd), "window should be maximized\n");
4747 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4748
4749 GetWindowRect(hwnd, &rc);
4750 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4751 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4752 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4753 DestroyWindow(hwnd);
4754 flush_sequence();
4755
4756 /* Test again, this time the NC_PAINT message */
4757 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4758 100, 100, 200, 200, 0, 0, 0, NULL);
4759 ok (hwnd != 0, "Failed to create popup window\n");
4760 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4761 flush_sequence();
4762 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4763 ok_sequence(WmShowMaxPopupResizedSeq_todo,
4764 "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", TRUE);
4765 DestroyWindow(hwnd);
4766 flush_sequence();
4767
4768 /* Test 2:
4769 * 1. Create invisible maximized popup window.
4770 * 2. Show it maximized.
4771 */
4772 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4773 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4774 100, 100, 200, 200, 0, 0, 0, NULL);
4775 ok (hwnd != 0, "Failed to create popup window\n");
4776 ok(IsZoomed(hwnd), "window should be maximized\n");
4777 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4778
4779 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4780 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4781 ok(IsZoomed(hwnd), "window should be maximized\n");
4782 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4783 DestroyWindow(hwnd);
4784 flush_sequence();
4785
4786 /* Test 3:
4787 * 1. Create visible maximized popup window.
4788 */
4789 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4790 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4791 100, 100, 200, 200, 0, 0, 0, NULL);
4792 ok (hwnd != 0, "Failed to create popup window\n");
4793 ok(IsZoomed(hwnd), "window should be maximized\n");
4794 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4795 DestroyWindow(hwnd);
4796 flush_sequence();
4797
4798 /* Test 4:
4799 * 1. Create visible popup window.
4800 * 2. Maximize it.
4801 */
4802 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4803 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4804 100, 100, 200, 200, 0, 0, 0, NULL);
4805 ok (hwnd != 0, "Failed to create popup window\n");
4806 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4807 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4808
4809 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4810 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4811 ok(IsZoomed(hwnd), "window should be maximized\n");
4812 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4813 DestroyWindow(hwnd);
4814 flush_sequence();
4815 }
4816
4817 static void test_sys_menu(void)
4818 {
4819 HWND hwnd;
4820 HMENU hmenu;
4821 UINT state;
4822
4823 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4824 100, 100, 200, 200, 0, 0, 0, NULL);
4825 ok (hwnd != 0, "Failed to create overlapped window\n");
4826
4827 flush_sequence();
4828
4829 /* test existing window without CS_NOCLOSE style */
4830 hmenu = GetSystemMenu(hwnd, FALSE);
4831 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4832
4833 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4834 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4835 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4836
4837 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4838 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4839
4840 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4841 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4842 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4843
4844 EnableMenuItem(hmenu, SC_CLOSE, 0);
4845 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4846
4847 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4848 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4849 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4850
4851 /* test whether removing WS_SYSMENU destroys a system menu */
4852 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4853 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4854 flush_sequence();
4855 hmenu = GetSystemMenu(hwnd, FALSE);
4856 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4857
4858 DestroyWindow(hwnd);
4859
4860 /* test new window with CS_NOCLOSE style */
4861 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4862 100, 100, 200, 200, 0, 0, 0, NULL);
4863 ok (hwnd != 0, "Failed to create overlapped window\n");
4864
4865 hmenu = GetSystemMenu(hwnd, FALSE);
4866 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4867
4868 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4869 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4870
4871 DestroyWindow(hwnd);
4872
4873 /* test new window without WS_SYSMENU style */
4874 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4875 100, 100, 200, 200, 0, 0, 0, NULL);
4876 ok(hwnd != 0, "Failed to create overlapped window\n");
4877
4878 hmenu = GetSystemMenu(hwnd, FALSE);
4879 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4880
4881 DestroyWindow(hwnd);
4882 }
4883
4884 /* For shown WS_OVERLAPPEDWINDOW */
4885 static const struct message WmSetIcon_1[] = {
4886 { WM_SETICON, sent },
4887 { 0x00AE, sent|defwinproc|optional }, /* XP */
4888 { WM_GETTEXT, sent|defwinproc|optional },
4889 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4890 { 0 }
4891 };
4892
4893 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4894 static const struct message WmSetIcon_2[] = {
4895 { WM_SETICON, sent },
4896 { 0 }
4897 };
4898
4899 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4900 static const struct message WmInitEndSession[] = {
4901 { 0x003B, sent },
4902 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4903 { 0 }
4904 };
4905
4906 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4907 static const struct message WmInitEndSession_2[] = {
4908 { 0x003B, sent },
4909 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4910 { 0 }
4911 };
4912
4913 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4914 static const struct message WmInitEndSession_3[] = {
4915 { 0x003B, sent },
4916 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4917 { 0 }
4918 };
4919
4920 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4921 static const struct message WmInitEndSession_4[] = {
4922 { 0x003B, sent },
4923 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4924 { 0 }
4925 };
4926
4927 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4928 static const struct message WmInitEndSession_5[] = {
4929 { 0x003B, sent },
4930 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4931 { 0 }
4932 };
4933
4934 static const struct message WmOptionalPaint[] = {
4935 { WM_PAINT, sent|optional },
4936 { WM_NCPAINT, sent|beginpaint|optional },
4937 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4938 { WM_ERASEBKGND, sent|beginpaint|optional },
4939 { 0 }
4940 };
4941
4942 static const struct message WmZOrder[] = {
4943 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4944 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4945 { HCBT_ACTIVATE, hook },
4946 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4947 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4948 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4949 { WM_GETTEXT, sent|optional },
4950 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4951 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4952 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4953 { WM_GETTEXT, sent|defwinproc|optional },
4954 { WM_GETTEXT, sent|defwinproc|optional },
4955 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4956 { HCBT_SETFOCUS, hook },
4957 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4958 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4959 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4960 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4961 { WM_GETTEXT, sent|optional },
4962 { WM_NCCALCSIZE, sent|optional },
4963 { 0 }
4964 };
4965
4966 static void CALLBACK apc_test_proc(ULONG_PTR param)
4967 {
4968 /* nothing */
4969 }
4970
4971 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4972 {
4973 DWORD ret;
4974 MSG msg;
4975
4976 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4977 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4978
4979 PostMessageA(hwnd, WM_USER, 0, 0);
4980
4981 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4982 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4983
4984 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4985 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4986
4987 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4988 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4989
4990 PostMessageA(hwnd, WM_USER, 0, 0);
4991
4992 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4993 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4994
4995 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4996 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4997
4998 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4999 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5000 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
5001
5002 PostMessageA(hwnd, WM_USER, 0, 0);
5003
5004 /* new incoming message causes it to become signaled again */
5005 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5006 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5007
5008 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5009 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5010 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5011 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5012
5013 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5014 PostMessageA( hwnd, WM_USER, 0, 0 );
5015 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5016 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5017
5018 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5019 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5020
5021 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5022 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5023
5024 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5025 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5026 ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5027
5028 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5029 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5030
5031 /* but even with MWMO_ALERTABLE window events are preferred */
5032 PostMessageA( hwnd, WM_USER, 0, 0 );
5033
5034 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5035 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5036
5037 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5038 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5039
5040 /* the APC call is still queued */
5041 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5042 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5043 }
5044
5045 static void test_WM_DEVICECHANGE(HWND hwnd)
5046 {
5047 DWORD ret;
5048 MSG msg;
5049 int i;
5050 static const WPARAM wparams[] = {0,
5051 DBT_DEVNODES_CHANGED,
5052 DBT_QUERYCHANGECONFIG,
5053 DBT_CONFIGCHANGED,
5054 DBT_CONFIGCHANGECANCELED,
5055 DBT_NO_DISK_SPACE,
5056 DBT_LOW_DISK_SPACE,
5057 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5058 DBT_DEVICEARRIVAL, /* 0x8000 */
5059 DBT_DEVICEQUERYREMOVE,
5060 DBT_DEVICEQUERYREMOVEFAILED,
5061 DBT_DEVICEREMOVEPENDING,
5062 DBT_DEVICEREMOVECOMPLETE,
5063 DBT_DEVICETYPESPECIFIC,
5064 DBT_CUSTOMEVENT};
5065
5066 for (i = 0; i < sizeof(wparams)/sizeof(wparams[0]); i++)
5067 {
5068 SetLastError(0xdeadbeef);
5069 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5070 if (wparams[i] & 0x8000)
5071 {
5072 ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5073 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5074 }
5075 else
5076 {
5077 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5078 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5079 memset(&msg, 0, sizeof(msg));
5080 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5081 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5082 }
5083 }
5084 }
5085
5086 static DWORD CALLBACK show_window_thread(LPVOID arg)
5087 {
5088 HWND hwnd = arg;
5089
5090 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5091 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5092
5093 return 0;
5094 }
5095
5096 /* Helper function to easier test SetWindowPos messages */
5097 #define test_msg_setpos( expected_list, flags, todo ) \
5098 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5099 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5100 {
5101 HWND hwnd;
5102
5103 flush_events();
5104 flush_sequence();
5105 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5106 10, 10, 100, 100, NULL, 0, 0, NULL );
5107 ok (hwnd != 0, "Failed to create popup window\n");
5108 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5109 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5110 DestroyWindow(hwnd);
5111 }
5112
5113 /* test if we receive the right sequence of messages */
5114 static void test_messages(void)
5115 {
5116 DWORD tid;
5117 HANDLE hthread;
5118 HWND hwnd, hparent, hchild;
5119 HWND hchild2, hbutton;
5120 HMENU hmenu;
5121 MSG msg;
5122 LRESULT res;
5123 POINT pos;
5124 BOOL ret;
5125
5126 flush_sequence();
5127
5128 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5129 100, 100, 200, 200, 0, 0, 0, NULL);
5130 ok (hwnd != 0, "Failed to create overlapped window\n");
5131 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5132
5133 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5134 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5135 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5136
5137 /* test WM_SETREDRAW on a not visible top level window */
5138 test_WM_SETREDRAW(hwnd);
5139
5140 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5141 flush_events();
5142 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5143 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5144
5145 ok(GetActiveWindow() == hwnd, "window should be active\n");
5146 ok(GetFocus() == hwnd, "window should have input focus\n");
5147 ShowWindow(hwnd, SW_HIDE);
5148 flush_events();
5149 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5150
5151 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5152 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5153 flush_events();
5154 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5155
5156 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5157 hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5158 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5159 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5160 CloseHandle(hthread);
5161 flush_events();
5162 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5163
5164 ShowWindow(hwnd, SW_SHOW);
5165 flush_events();
5166 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5167
5168 ShowWindow(hwnd, SW_HIDE);
5169 flush_events();
5170 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5171
5172 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5173 flush_events();
5174 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5175 flush_sequence();
5176
5177 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5178 {
5179 ShowWindow(hwnd, SW_RESTORE);
5180 flush_events();
5181 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5182 flush_sequence();
5183 }
5184
5185 ShowWindow(hwnd, SW_MINIMIZE);
5186 flush_events();
5187 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5188 flush_sequence();
5189
5190 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5191 {
5192 ShowWindow(hwnd, SW_RESTORE);
5193 flush_events();
5194 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5195 flush_sequence();
5196 }
5197
5198 ShowWindow(hwnd, SW_SHOW);
5199 flush_events();
5200 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5201
5202 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5203 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5204 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5205 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5206
5207 /* test WM_SETREDRAW on a visible top level window */
5208 ShowWindow(hwnd, SW_SHOW);
5209 flush_events();
5210 test_WM_SETREDRAW(hwnd);
5211
5212 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5213 test_scroll_messages(hwnd);
5214
5215 /* test resizing and moving */
5216 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5217 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5218 flush_events();
5219 flush_sequence();
5220 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5221 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5222 flush_events();
5223 flush_sequence();
5224 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5225 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5226 flush_events();
5227 flush_sequence();
5228
5229 /* popups don't get WM_GETMINMAXINFO */
5230 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5231 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5232 flush_sequence();
5233 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5234 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5235
5236 DestroyWindow(hwnd);
5237 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5238
5239 /* Test if windows are correctly drawn when first shown */
5240
5241 /* Visible, redraw */
5242 flush_events();
5243 flush_sequence();
5244 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5245 10, 10, 100, 100, NULL, 0, 0, NULL );
5246 ok (hwnd != 0, "Failed to create popup window\n");
5247 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5248 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5249 DestroyWindow(hwnd);
5250
5251 /* Invisible, show, message */
5252 flush_events();
5253 flush_sequence();
5254 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5255 10, 10, 100, 100, NULL, 0, 0, NULL );
5256 ok (hwnd != 0, "Failed to create popup window\n");
5257 ShowWindow(hwnd, SW_SHOW);
5258 SendMessageW(hwnd, WM_PAINT, 0, 0);
5259 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5260 DestroyWindow(hwnd);
5261
5262 /* Invisible, show maximized, redraw */
5263 flush_events();
5264 flush_sequence();
5265 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5266 10, 10, 100, 100, NULL, 0, 0, NULL );
5267 ok (hwnd != 0, "Failed to create popup window\n");
5268 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5269 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5270 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5271 DestroyWindow(hwnd);
5272
5273 /* Test SetWindowPos */
5274 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5275 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5276 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5277 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5278
5279 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5280 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5281 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5282 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5283 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5284
5285 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5286 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5287 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5288 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5289 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5290 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5291
5292 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5293 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5294 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5295 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5296 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5297 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5298
5299 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5300 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5301 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5302 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5303 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5304 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5305
5306 /* Test SetWindowPos with child windows */
5307 flush_events();
5308 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5309 100, 100, 200, 200, 0, 0, 0, NULL);
5310 ok (hparent != 0, "Failed to create parent window\n");
5311
5312 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5313 0, 0, 10, 10, hparent, 0, 0, NULL);
5314 ok (hchild != 0, "Failed to create child window\n");
5315 flush_sequence();
5316 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5317 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5318 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5319 DestroyWindow(hchild);
5320 DestroyWindow(hparent);
5321
5322 flush_events();
5323 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5324 100, 100, 200, 200, 0, 0, 0, NULL);
5325 ok (hparent != 0, "Failed to create parent window\n");
5326
5327 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5328 0, 0, 10, 10, hparent, 0, 0, NULL);
5329 ok (hchild != 0, "Failed to create child window\n");
5330 flush_sequence();
5331 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5332 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5333 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5334 DestroyWindow(hchild);
5335 DestroyWindow(hparent);
5336
5337 /* Test message sequence for extreme position and size */
5338
5339 flush_sequence();
5340 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5341 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5342 ok (hwnd != 0, "Failed to create popup window\n");
5343 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE);
5344 DestroyWindow(hwnd);
5345
5346
5347 /* Test child windows */
5348
5349 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5350 100, 100, 200, 200, 0, 0, 0, NULL);
5351 ok (hparent != 0, "Failed to create parent window\n");
5352 flush_sequence();
5353
5354 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5355 0, 0, 10, 10, hparent, 0, 0, NULL);
5356 ok (hchild != 0, "Failed to create child window\n");
5357 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5358 DestroyWindow(hchild);
5359 flush_sequence();
5360
5361 /* visible child window with a caption */
5362 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5363 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5364 0, 0, 10, 10, hparent, 0, 0, NULL);
5365 ok (hchild != 0, "Failed to create child window\n");
5366 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5367
5368 trace("testing scroll APIs on a visible child window %p\n", hchild);
5369 test_scroll_messages(hchild);
5370
5371 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5372 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5373
5374 DestroyWindow(hchild);
5375 flush_sequence();
5376
5377 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5378 0, 0, 10, 10, hparent, 0, 0, NULL);
5379 ok (hchild != 0, "Failed to create child window\n");
5380 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5381
5382 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5383 100, 100, 50, 50, hparent, 0, 0, NULL);
5384 ok (hchild2 != 0, "Failed to create child2 window\n");
5385 flush_sequence();
5386
5387 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5388 0, 100, 50, 50, hchild, 0, 0, NULL);
5389 ok (hbutton != 0, "Failed to create button window\n");
5390
5391 /* test WM_SETREDRAW on a not visible child window */
5392 test_WM_SETREDRAW(hchild);
5393
5394 ShowWindow(hchild, SW_SHOW);
5395 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5396
5397 /* check parent messages too */
5398 log_all_parent_messages++;
5399 ShowWindow(hchild, SW_HIDE);
5400 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5401 log_all_parent_messages--;
5402
5403 ShowWindow(hchild, SW_SHOW);
5404 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5405
5406 ShowWindow(hchild, SW_HIDE);
5407 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5408
5409 ShowWindow(hchild, SW_SHOW);
5410 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5411
5412 /* test WM_SETREDRAW on a visible child window */
5413 test_WM_SETREDRAW(hchild);
5414
5415 log_all_parent_messages++;
5416 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5417 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5418 log_all_parent_messages--;
5419
5420 ShowWindow(hchild, SW_HIDE);
5421 flush_sequence();
5422 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5423 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5424
5425 ShowWindow(hchild, SW_HIDE);
5426 flush_sequence();
5427 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5428 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5429
5430 /* DestroyWindow sequence below expects that a child has focus */
5431 SetFocus(hchild);
5432 flush_sequence();
5433
5434 DestroyWindow(hchild);
5435 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5436 DestroyWindow(hchild2);
5437 DestroyWindow(hbutton);
5438
5439 flush_sequence();
5440 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5441 0, 0, 100, 100, hparent, 0, 0, NULL);
5442 ok (hchild != 0, "Failed to create child popup window\n");
5443 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5444 DestroyWindow(hchild);
5445
5446 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5447 flush_sequence();
5448 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5449 0, 0, 100, 100, hparent, 0, 0, NULL);
5450 ok (hchild != 0, "Failed to create popup window\n");
5451 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5452 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5453 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5454 flush_sequence();
5455 ShowWindow(hchild, SW_SHOW);
5456 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5457 flush_sequence();
5458 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5459 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5460 flush_sequence();
5461 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5462 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5463 DestroyWindow(hchild);
5464
5465 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5466 * changes nothing in message sequences.
5467 */
5468 flush_sequence();
5469 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5470 0, 0, 100, 100, hparent, 0, 0, NULL);
5471 ok (hchild != 0, "Failed to create popup window\n");
5472 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5473 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5474 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5475 flush_sequence();
5476 ShowWindow(hchild, SW_SHOW);
5477 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5478 flush_sequence();
5479 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5480 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5481 DestroyWindow(hchild);
5482
5483 flush_sequence();
5484 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5485 0, 0, 100, 100, hparent, 0, 0, NULL);
5486 ok(hwnd != 0, "Failed to create custom dialog window\n");
5487 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5488
5489 if(0) {
5490 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5491 test_scroll_messages(hwnd);
5492 }
5493
5494 flush_sequence();
5495
5496 test_def_id = TRUE;
5497 SendMessageA(hwnd, WM_NULL, 0, 0);
5498
5499 flush_sequence();
5500 after_end_dialog = TRUE;
5501 EndDialog( hwnd, 0 );
5502 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5503
5504 DestroyWindow(hwnd);
5505 after_end_dialog = FALSE;
5506 test_def_id = FALSE;
5507
5508 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5509 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5510
5511 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5512 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5513 ok(hwnd != 0, "Failed to create custom dialog window\n");
5514 flush_sequence();
5515 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5516 ShowWindow(hwnd, SW_SHOW);
5517 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5518
5519 flush_events();
5520 flush_sequence();
5521 ret = DrawMenuBar(hwnd);
5522 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5523 flush_events();
5524 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5525 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5526
5527 DestroyWindow(hwnd);
5528
5529 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5530 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5531 ok(hwnd != 0, "Failed to create custom dialog window\n");
5532 flush_events();
5533 flush_sequence();
5534 ret = DrawMenuBar(hwnd);
5535 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5536 flush_events();
5537 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5538
5539 DestroyWindow(hwnd);
5540
5541 flush_sequence();
5542 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5543 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5544
5545 DestroyWindow(hparent);
5546 flush_sequence();
5547
5548 /* Message sequence for SetMenu */
5549 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5550 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5551 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5552
5553 hmenu = CreateMenu();
5554 ok (hmenu != 0, "Failed to create menu\n");
5555 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5556 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5557 100, 100, 200, 200, 0, hmenu, 0, NULL);
5558 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5559 ok (SetMenu(hwnd, 0), "SetMenu\n");
5560 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5561 ok (SetMenu(hwnd, 0), "SetMenu\n");
5562 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5563 ShowWindow(hwnd, SW_SHOW);
5564 UpdateWindow( hwnd );
5565 flush_events();
5566 flush_sequence();
5567 ok (SetMenu(hwnd, 0), "SetMenu\n");
5568 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5569 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5570 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5571
5572 UpdateWindow( hwnd );
5573 flush_events();
5574 flush_sequence();
5575 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5576 flush_events();
5577 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5578
5579 DestroyWindow(hwnd);
5580 flush_sequence();
5581
5582 /* Message sequence for EnableWindow */
5583 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5584 100, 100, 200, 200, 0, 0, 0, NULL);
5585 ok (hparent != 0, "Failed to create parent window\n");
5586 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5587 0, 0, 10, 10, hparent, 0, 0, NULL);
5588 ok (hchild != 0, "Failed to create child window\n");
5589
5590 SetFocus(hchild);
5591 flush_events();
5592 flush_sequence();
5593
5594 EnableWindow(hparent, FALSE);
5595 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5596
5597 EnableWindow(hparent, FALSE);
5598 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5599
5600 EnableWindow(hparent, TRUE);
5601 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5602
5603 EnableWindow(hparent, TRUE);
5604 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5605
5606 flush_events();
5607 flush_sequence();
5608
5609 test_MsgWaitForMultipleObjects(hparent);
5610 test_WM_DEVICECHANGE(hparent);
5611
5612 /* the following test causes an exception in user.exe under win9x */
5613 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5614 {
5615 DestroyWindow(hparent);
5616 flush_sequence();
5617 return;
5618 }
5619 PostMessageW( hparent, WM_USER+1, 0, 0 );
5620 /* PeekMessage(NULL) fails, but still removes the message */
5621 SetLastError(0xdeadbeef);
5622 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5623 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5624 GetLastError() == 0xdeadbeef, /* NT4 */
5625 "last error is %d\n", GetLastError() );
5626 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5627 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5628
5629 DestroyWindow(hchild);
5630 DestroyWindow(hparent);
5631 flush_sequence();
5632
5633 /* Message sequences for WM_SETICON */
5634 trace("testing WM_SETICON\n");
5635 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5636 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5637 NULL, NULL, 0);
5638 ShowWindow(hwnd, SW_SHOW);
5639 UpdateWindow(hwnd);
5640 flush_events();
5641 flush_sequence();
5642 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5643 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5644
5645 ShowWindow(hwnd, SW_HIDE);
5646 flush_events();
5647 flush_sequence();
5648 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5649 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5650 DestroyWindow(hwnd);
5651 flush_sequence();
5652
5653 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5654 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5655 NULL, NULL, 0);
5656 ShowWindow(hwnd, SW_SHOW);
5657 UpdateWindow(hwnd);
5658 flush_events();
5659 flush_sequence();
5660 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5661 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5662
5663 ShowWindow(hwnd, SW_HIDE);
5664 flush_events();
5665 flush_sequence();
5666 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5667 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5668
5669 flush_sequence();
5670 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5671 if (!res)
5672 {
5673 todo_wine win_skip( "Message 0x3b not supported\n" );
5674 goto done;
5675 }
5676 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5677 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5678 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5679 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5680 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5681 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5682 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5683 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5684
5685 flush_sequence();
5686 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5687 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5688 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5689 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5690 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5691 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5692
5693 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5694 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5695 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5696
5697 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5698 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5699 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5700
5701 done:
5702 DestroyWindow(hwnd);
5703 flush_sequence();
5704 }
5705
5706 static void test_setwindowpos(void)
5707 {
5708 HWND hwnd;
5709 RECT rc;
5710 LRESULT res;
5711 const INT winX = 100;
5712 const INT winY = 100;
5713 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5714
5715 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5716 0, 0, winX, winY, 0,
5717 NULL, NULL, 0);
5718
5719 GetWindowRect(hwnd, &rc);
5720 expect(sysX, rc.right);
5721 expect(winY, rc.bottom);
5722
5723 flush_events();
5724 flush_sequence();
5725 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5726 ok_sequence(WmZOrder, "Z-Order", TRUE);
5727 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5728
5729 GetWindowRect(hwnd, &rc);
5730 expect(sysX, rc.right);
5731 expect(winY, rc.bottom);
5732 DestroyWindow(hwnd);
5733 }
5734
5735 static void invisible_parent_tests(void)
5736 {
5737 HWND hparent, hchild;
5738
5739 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5740 100, 100, 200, 200, 0, 0, 0, NULL);
5741 ok (hparent != 0, "Failed to create parent window\n");
5742 flush_sequence();
5743
5744 /* test showing child with hidden parent */
5745
5746 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5747 0, 0, 10, 10, hparent, 0, 0, NULL);
5748 ok (hchild != 0, "Failed to create child window\n");
5749 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5750
5751 ShowWindow( hchild, SW_MINIMIZE );
5752 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5753 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5754 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5755
5756 /* repeat */
5757 flush_events();
5758 flush_sequence();
5759 ShowWindow( hchild, SW_MINIMIZE );
5760 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5761
5762 DestroyWindow(hchild);
5763 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5764 0, 0, 10, 10, hparent, 0, 0, NULL);
5765 flush_sequence();
5766
5767 ShowWindow( hchild, SW_MAXIMIZE );
5768 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5769 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5770 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5771
5772 /* repeat */
5773 flush_events();
5774 flush_sequence();
5775 ShowWindow( hchild, SW_MAXIMIZE );
5776 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5777
5778 DestroyWindow(hchild);
5779 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5780 0, 0, 10, 10, hparent, 0, 0, NULL);
5781 flush_sequence();
5782
5783 ShowWindow( hchild, SW_RESTORE );
5784 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5785 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5786 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5787
5788 DestroyWindow(hchild);
5789 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5790 0, 0, 10, 10, hparent, 0, 0, NULL);
5791 flush_sequence();
5792
5793 ShowWindow( hchild, SW_SHOWMINIMIZED );
5794 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5795 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5796 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5797
5798 /* repeat */
5799 flush_events();
5800 flush_sequence();
5801 ShowWindow( hchild, SW_SHOWMINIMIZED );
5802 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5803
5804 DestroyWindow(hchild);
5805 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5806 0, 0, 10, 10, hparent, 0, 0, NULL);
5807 flush_sequence();
5808
5809 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5810 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5811 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5812 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5813 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5814
5815 DestroyWindow(hchild);
5816 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5817 0, 0, 10, 10, hparent, 0, 0, NULL);
5818 flush_sequence();
5819
5820 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5821 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5822 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5823 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5824
5825 /* repeat */
5826 flush_events();
5827 flush_sequence();
5828 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5829 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5830
5831 DestroyWindow(hchild);
5832 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5833 0, 0, 10, 10, hparent, 0, 0, NULL);
5834 flush_sequence();
5835
5836 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5837 ShowWindow( hchild, SW_FORCEMINIMIZE );
5838 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5839 todo_wine {
5840 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5841 }
5842 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5843
5844 DestroyWindow(hchild);
5845 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5846 0, 0, 10, 10, hparent, 0, 0, NULL);
5847 flush_sequence();
5848
5849 ShowWindow( hchild, SW_SHOWNA );
5850 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5851 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5852 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5853
5854 /* repeat */
5855 flush_events();
5856 flush_sequence();
5857 ShowWindow( hchild, SW_SHOWNA );
5858 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5859
5860 DestroyWindow(hchild);
5861 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5862 0, 0, 10, 10, hparent, 0, 0, NULL);
5863 flush_sequence();
5864
5865 ShowWindow( hchild, SW_SHOW );
5866 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5867 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5868 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5869
5870 /* repeat */
5871 flush_events();
5872 flush_sequence();
5873 ShowWindow( hchild, SW_SHOW );
5874 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5875
5876 ShowWindow( hchild, SW_HIDE );
5877 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5878 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5879 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5880
5881 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5882 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5883 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5884 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5885
5886 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5887 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5888 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5889 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5890
5891 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5892 flush_sequence();
5893 DestroyWindow(hchild);
5894 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5895
5896 DestroyWindow(hparent);
5897 flush_sequence();
5898 }
5899
5900 /****************** button message test *************************/
5901 #define ID_BUTTON 0x000e
5902
5903 static const struct message WmSetFocusButtonSeq[] =
5904 {
5905 { HCBT_SETFOCUS, hook },
5906 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5907 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5908 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5909 { WM_SETFOCUS, sent|wparam, 0 },
5910 { WM_CTLCOLORBTN, sent|parent },
5911 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5912 { WM_APP, sent|wparam|lparam, 0, 0 },
5913 { 0 }
5914 };
5915 static const struct message WmKillFocusButtonSeq[] =
5916 {
5917 { HCBT_SETFOCUS, hook },
5918 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5919 { WM_KILLFOCUS, sent|wparam, 0 },
5920 { WM_CTLCOLORBTN, sent|parent },
5921 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5922 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5923 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5924 { WM_APP, sent|wparam|lparam, 0, 0 },
5925 { WM_PAINT, sent },
5926 { WM_CTLCOLORBTN, sent|parent },
5927 { 0 }
5928 };
5929 static const struct message WmSetFocusStaticSeq[] =
5930 {
5931 { HCBT_SETFOCUS, hook },
5932 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5933 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5934 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5935 { WM_SETFOCUS, sent|wparam, 0 },
5936 { WM_CTLCOLORSTATIC, sent|parent },
5937 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5938 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5939 { WM_APP, sent|wparam|lparam, 0, 0 },
5940 { 0 }
5941 };
5942 static const struct message WmKillFocusStaticSeq[] =
5943 {
5944 { HCBT_SETFOCUS, hook },
5945 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5946 { WM_KILLFOCUS, sent|wparam, 0 },
5947 { WM_CTLCOLORSTATIC, sent|parent },
5948 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5949 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5950 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5951 { WM_APP, sent|wparam|lparam, 0, 0 },
5952 { WM_PAINT, sent },
5953 { WM_CTLCOLORSTATIC, sent|parent },
5954 { 0 }
5955 };
5956 static const struct message WmSetFocusOwnerdrawSeq[] =
5957 {
5958 { HCBT_SETFOCUS, hook },
5959 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5960 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5961 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5962 { WM_SETFOCUS, sent|wparam, 0 },
5963 { WM_CTLCOLORBTN, sent|parent },
5964 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5965 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5966 { WM_APP, sent|wparam|lparam, 0, 0 },
5967 { 0 }
5968 };
5969 static const struct message WmKillFocusOwnerdrawSeq[] =
5970 {
5971 { HCBT_SETFOCUS, hook },
5972 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5973 { WM_KILLFOCUS, sent|wparam, 0 },
5974 { WM_CTLCOLORBTN, sent|parent },
5975 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5976 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5977 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5978 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5979 { WM_APP, sent|wparam|lparam, 0, 0 },
5980 { WM_PAINT, sent },
5981 { WM_CTLCOLORBTN, sent|parent },
5982 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5983 { 0 }
5984 };
5985 static const struct message WmLButtonDownSeq[] =
5986 {
5987 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5988 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5989 { HCBT_SETFOCUS, hook },
5990 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5991 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5992 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5993 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5994 { WM_CTLCOLORBTN, sent|defwinproc },
5995 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5996 { WM_CTLCOLORBTN, sent|defwinproc },
5997 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5998 { 0 }
5999 };
6000 static const struct message WmLButtonDownStaticSeq[] =
6001 {
6002 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6003 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6004 { HCBT_SETFOCUS, hook },
6005 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6006 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6007 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6008 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6009 { WM_CTLCOLORSTATIC, sent|defwinproc },
6010 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6011 { WM_CTLCOLORSTATIC, sent|defwinproc },
6012 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6013 { 0 }
6014 };
6015 static const struct message WmLButtonUpSeq[] =
6016 {
6017 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6018 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6019 { WM_CTLCOLORBTN, sent|defwinproc },
6020 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6021 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6022 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6023 { 0 }
6024 };
6025 static const struct message WmLButtonUpStaticSeq[] =
6026 {
6027 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6028 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6029 { WM_CTLCOLORSTATIC, sent|defwinproc },
6030 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6031 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6032 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6033 { 0 }
6034 };
6035 static const struct message WmLButtonUpAutoSeq[] =
6036 {
6037 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6038 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6039 { WM_CTLCOLORSTATIC, sent|defwinproc },
6040 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6041 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6042 { BM_SETCHECK, sent|defwinproc },
6043 { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6044 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6045 { 0 }
6046 };
6047 static const struct message WmLButtonUpBrokenSeq[] =
6048 {
6049 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6050 { 0 }
6051 };
6052 static const struct message WmSetFontButtonSeq[] =
6053 {
6054 { WM_SETFONT, sent },
6055 { WM_PAINT, sent },
6056 { WM_ERASEBKGND, sent|defwinproc|optional },
6057 { WM_CTLCOLORBTN, sent|defwinproc },
6058 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6059 { 0 }
6060 };
6061 static const struct message WmSetFontStaticSeq[] =
6062 {
6063 { WM_SETFONT, sent },
6064 { WM_PAINT, sent },
6065 { WM_ERASEBKGND, sent|defwinproc|optional },
6066 { WM_CTLCOLORSTATIC, sent|defwinproc },
6067 { 0 }
6068 };
6069 static const struct message WmSetTextButtonSeq[] =
6070 {
6071 { WM_SETTEXT, sent },
6072 { WM_CTLCOLORBTN, sent|parent },
6073 { WM_CTLCOLORBTN, sent|parent },
6074 { WM_COMMAND, sent|parent|optional },
6075 { WM_DRAWITEM, sent|parent|optional },
6076 { 0 }
6077 };
6078 static const struct message WmSetTextStaticSeq[] =
6079 {
6080 { WM_SETTEXT, sent },
6081 { WM_CTLCOLORSTATIC, sent|parent },
6082 { WM_CTLCOLORSTATIC, sent|parent },
6083 { 0 }
6084 };
6085 static const struct message WmSetTextGroupSeq[] =
6086 {
6087 { WM_SETTEXT, sent },
6088 { WM_CTLCOLORSTATIC, sent|parent },
6089 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6090 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6091 { 0 }
6092 };
6093 static const struct message WmSetTextInvisibleSeq[] =
6094 {
6095 { WM_SETTEXT, sent },
6096 { 0 }
6097 };
6098 static const struct message WmSetStyleButtonSeq[] =
6099 {
6100 { BM_SETSTYLE, sent },
6101 { WM_APP, sent|wparam|lparam, 0, 0 },
6102 { WM_PAINT, sent },
6103 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6104 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6105 { WM_CTLCOLORBTN, sent|parent },
6106 { 0 }
6107 };
6108 static const struct message WmSetStyleStaticSeq[] =
6109 {
6110 { BM_SETSTYLE, sent },
6111 { WM_APP, sent|wparam|lparam, 0, 0 },
6112 { WM_PAINT, sent },
6113 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6114 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6115 { WM_CTLCOLORSTATIC, sent|parent },
6116 { 0 }
6117 };
6118 static const struct message WmSetStyleUserSeq[] =
6119 {
6120 { BM_SETSTYLE, sent },
6121 { WM_APP, sent|wparam|lparam, 0, 0 },
6122 { WM_PAINT, sent },
6123 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6124 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6125 { WM_CTLCOLORBTN, sent|parent },
6126 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6127 { 0 }
6128 };
6129 static const struct message WmSetStyleOwnerdrawSeq[] =
6130 {
6131 { BM_SETSTYLE, sent },
6132 { WM_APP, sent|wparam|lparam, 0, 0 },
6133 { WM_PAINT, sent },
6134 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6135 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6136 { WM_CTLCOLORBTN, sent|parent },
6137 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6138 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6139 { 0 }
6140 };
6141 static const struct message WmSetStateButtonSeq[] =
6142 {
6143 { BM_SETSTATE, sent },
6144 { WM_CTLCOLORBTN, sent|parent },
6145 { WM_APP, sent|wparam|lparam, 0, 0 },
6146 { 0 }
6147 };
6148 static const struct message WmSetStateStaticSeq[] =
6149 {
6150 { BM_SETSTATE, sent },
6151 { WM_CTLCOLORSTATIC, sent|parent },
6152 { WM_APP, sent|wparam|lparam, 0, 0 },
6153 { 0 }
6154 };
6155 static const struct message WmSetStateUserSeq[] =
6156 {
6157 { BM_SETSTATE, sent },
6158 { WM_CTLCOLORBTN, sent|parent },
6159 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6160 { WM_APP, sent|wparam|lparam, 0, 0 },
6161 { 0 }
6162 };
6163 static const struct message WmSetStateOwnerdrawSeq[] =
6164 {
6165 { BM_SETSTATE, sent },
6166 { WM_CTLCOLORBTN, sent|parent },
6167 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6168 { WM_APP, sent|wparam|lparam, 0, 0 },
6169 { 0 }
6170 };
6171 static const struct message WmClearStateButtonSeq[] =
6172 {
6173 { BM_SETSTATE, sent },
6174 { WM_CTLCOLORBTN, sent|parent },
6175 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6176 { WM_APP, sent|wparam|lparam, 0, 0 },
6177 { 0 }
6178 };
6179 static const struct message WmDisableButtonSeq[] =
6180 {
6181 { WM_LBUTTONDOWN, sent },
6182 { BM_SETSTATE, sent|defwinproc },
6183 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6184 { WM_CTLCOLORBTN, sent|optional },
6185 { WM_LBUTTONUP, sent },
6186 { BM_SETSTATE, sent|defwinproc },
6187 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6188 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6189 { BM_SETCHECK, sent|defwinproc|optional },
6190 { WM_CTLCOLORBTN, sent|optional },
6191 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6192 { WM_CAPTURECHANGED, sent|defwinproc },
6193 { WM_COMMAND, sent },
6194 { 0 }
6195 };
6196 static const struct message WmClearStateOwnerdrawSeq[] =
6197 {
6198 { BM_SETSTATE, sent },
6199 { WM_CTLCOLORBTN, sent|parent },
6200 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6201 { WM_APP, sent|wparam|lparam, 0, 0 },
6202 { 0 }
6203 };
6204 static const struct message WmSetCheckIgnoredSeq[] =
6205 {
6206 { BM_SETCHECK, sent },
6207 { WM_APP, sent|wparam|lparam, 0, 0 },
6208 { 0 }
6209 };
6210 static const struct message WmSetCheckStaticSeq[] =
6211 {
6212 { BM_SETCHECK, sent },
6213 { WM_CTLCOLORSTATIC, sent|parent },
6214 { WM_APP, sent|wparam|lparam, 0, 0 },
6215 { 0 }
6216 };
6217
6218 static WNDPROC old_button_proc;
6219
6220 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6221 {
6222 static LONG defwndproc_counter = 0;
6223 LRESULT ret;
6224 struct recvd_message msg;
6225
6226 if (ignore_message( message )) return 0;
6227
6228 switch (message)
6229 {
6230 case WM_SYNCPAINT:
6231 break;
6232 case BM_SETSTATE:
6233 if (GetCapture())
6234 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6235
6236 lParam = (ULONG_PTR)GetMenu(hwnd);
6237 goto log_it;
6238
6239 case WM_GETDLGCODE:
6240 if (lParam)
6241 {
6242 MSG *msg = (MSG *)lParam;
6243 lParam = MAKELPARAM(msg->message, msg->wParam);
6244 }
6245 wParam = (ULONG_PTR)GetMenu(hwnd);
6246 goto log_it;
6247
6248 case BM_SETCHECK:
6249 case BM_GETCHECK:
6250 lParam = (ULONG_PTR)GetMenu(hwnd);
6251 /* fall through */
6252 log_it:
6253 default:
6254 msg.hwnd = hwnd;
6255 msg.message = message;
6256 msg.flags = sent|wparam|lparam;
6257 if (defwndproc_counter) msg.flags |= defwinproc;
6258 msg.wParam = wParam;
6259 msg.lParam = lParam;
6260 msg.descr = "button";
6261 add_message(&msg);
6262 }
6263
6264 defwndproc_counter++;
6265 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6266 defwndproc_counter--;
6267
6268 return ret;
6269 }
6270
6271 static void subclass_button(void)
6272 {
6273 WNDCLASSA cls;
6274
6275 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6276
6277 old_button_proc = cls.lpfnWndProc;
6278
6279 cls.hInstance = GetModuleHandleA(NULL);
6280 cls.lpfnWndProc = button_hook_proc;
6281 cls.lpszClassName = "my_button_class";
6282 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6283 if (!RegisterClassA(&cls)) assert(0);
6284 }
6285
6286 static void test_button_messages(void)
6287 {
6288 static const struct
6289 {
6290 DWORD style;
6291 DWORD dlg_code;
6292 const struct message *setfocus;
6293 const struct message *killfocus;
6294 const struct message *setstyle;
6295 const struct message *setstate;
6296 const struct message *clearstate;
6297 const struct message *setcheck;
6298 const struct message *lbuttondown;
6299 const struct message *lbuttonup;
6300 const struct message *setfont;
6301 const struct message *settext;
6302 } button[] = {
6303 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6304 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6305 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6306 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6307 WmSetTextButtonSeq },
6308 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6309 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6310 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6311 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6312 WmSetTextButtonSeq },
6313 { BS_CHECKBOX, DLGC_BUTTON,
6314 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6315 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6316 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6317 WmSetTextStaticSeq },
6318 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6319 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6320 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6321 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6322 WmSetTextStaticSeq },
6323 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6324 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6325 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6326 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6327 WmSetTextStaticSeq },
6328 { BS_3STATE, DLGC_BUTTON,
6329 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6330 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6331 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6332 WmSetTextStaticSeq },
6333 { BS_AUTO3STATE, DLGC_BUTTON,
6334 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6335 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6336 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6337 WmSetTextStaticSeq },
6338 { BS_GROUPBOX, DLGC_STATIC,
6339 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6340 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6341 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6342 WmSetTextGroupSeq },
6343 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6344 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6345 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6346 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6347 WmSetTextButtonSeq },
6348 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6349 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6350 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6351 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6352 WmSetTextStaticSeq },
6353 { BS_OWNERDRAW, DLGC_BUTTON,
6354 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6355 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6356 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6357 WmSetTextButtonSeq },
6358 };
6359 LOGFONTA logfont = { 0 };
6360 HFONT zfont, hfont2;
6361 unsigned int i;
6362 HWND hwnd, parent;
6363 DWORD dlg_code;
6364
6365 /* selection with VK_SPACE should capture button window */
6366 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6367 0, 0, 50, 14, 0, 0, 0, NULL);
6368 ok(hwnd != 0, "Failed to create button window\n");
6369 ReleaseCapture();
6370 SetFocus(hwnd);
6371 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6372 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6373 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6374 DestroyWindow(hwnd);
6375
6376 subclass_button();
6377
6378 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6379 100, 100, 200, 200, 0, 0, 0, NULL);
6380 ok(parent != 0, "Failed to create parent window\n");
6381
6382 memset(&logfont, 0, sizeof(logfont));
6383 logfont.lfHeight = -12;
6384 logfont.lfWeight = FW_NORMAL;
6385 strcpy(logfont.lfFaceName, "Tahoma");
6386
6387 hfont2 = CreateFontIndirectA(&logfont);
6388 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6389
6390 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
6391 {
6392 MSG msg;
6393 DWORD style, state;
6394 HFONT prevfont;
6395 char desc[64];
6396 HDC hdc;
6397
6398 trace("button style %08x\n", button[i].style);
6399
6400 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6401 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6402 ok(hwnd != 0, "Failed to create button window\n");
6403
6404 style = GetWindowLongA(hwnd, GWL_STYLE);
6405 style &= ~(WS_CHILD | BS_NOTIFY);
6406 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6407 if (button[i].style == BS_USERBUTTON)
6408 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6409 else
6410 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6411
6412 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6413 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6414
6415 ShowWindow(hwnd, SW_SHOW);
6416 UpdateWindow(hwnd);
6417 SetFocus(0);
6418 flush_events();
6419 SetFocus(0);
6420 flush_sequence();
6421
6422 log_all_parent_messages++;
6423
6424 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6425 SetFocus(hwnd);
6426 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6427 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6428 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6429
6430 SetFocus(0);
6431 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6432 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6433 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6434
6435 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6436
6437 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6438 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6439 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6440 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6441
6442 style = GetWindowLongA(hwnd, GWL_STYLE);
6443 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6444 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6445 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6446
6447 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6448 ok(state == 0, "expected state 0, got %04x\n", state);
6449
6450 flush_sequence();
6451
6452 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6453 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6454 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6455 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6456
6457 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6458 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6459
6460 style = GetWindowLongA(hwnd, GWL_STYLE);
6461 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6462 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6463
6464 flush_sequence();
6465
6466 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6467 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6468 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6469 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6470
6471 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6472 ok(state == 0, "expected state 0, got %04x\n", state);
6473
6474 style = GetWindowLongA(hwnd, GWL_STYLE);
6475 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6476 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6477
6478 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6479 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6480
6481 flush_sequence();
6482
6483 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6484 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6485 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6486 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6487
6488 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6489 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6490
6491 style = GetWindowLongA(hwnd, GWL_STYLE);
6492 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6493 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6494
6495 flush_sequence();
6496
6497 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6498 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6499 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6500 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6501
6502 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6503 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6504 ok_sequence(button[i].settext, desc, FALSE);
6505
6506 ShowWindow(hwnd, SW_HIDE);
6507 flush_events();
6508 flush_sequence();
6509
6510 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6511 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6512 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6513
6514 ShowWindow(hwnd, SW_SHOW);
6515 ShowWindow(parent, SW_HIDE);
6516 flush_events();
6517 flush_sequence();
6518
6519 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6520 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6521 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6522
6523 ShowWindow(parent, SW_SHOW);
6524 flush_events();
6525
6526 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6527 if (button[i].style == BS_PUSHBUTTON ||
6528 button[i].style == BS_DEFPUSHBUTTON ||
6529 button[i].style == BS_GROUPBOX ||
6530 button[i].style == BS_USERBUTTON ||
6531 button[i].style == BS_OWNERDRAW)
6532 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6533 else
6534 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6535
6536 style = GetWindowLongA(hwnd, GWL_STYLE);
6537 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6538 if (button[i].style == BS_RADIOBUTTON ||
6539 button[i].style == BS_AUTORADIOBUTTON)
6540 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6541 else
6542 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6543
6544 log_all_parent_messages--;
6545
6546 DestroyWindow(hwnd);
6547
6548 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6549 0, 0, 50, 14, 0, 0, 0, NULL);
6550 ok(hwnd != 0, "Failed to create button window\n");
6551
6552 SetForegroundWindow(hwnd);
6553 flush_events();
6554
6555 SetActiveWindow(hwnd);
6556 SetFocus(0);
6557 flush_sequence();
6558
6559 if (button[i].lbuttondown)
6560 {
6561 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6562 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6563 ok_sequence(button[i].lbuttondown, desc, FALSE);
6564 }
6565
6566 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6567 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6568 ok_sequence(button[i].lbuttonup, desc, FALSE);
6569
6570 flush_sequence();
6571 zfont = GetStockObject(DEFAULT_GUI_FONT);
6572 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6573 UpdateWindow(hwnd);
6574 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6575 ok_sequence(button[i].setfont, desc, FALSE);
6576
6577 /* Test that original font is not selected back after painting */
6578 hdc = CreateCompatibleDC(0);
6579
6580 prevfont = SelectObject(hdc, hfont2);
6581 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6582 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6583 todo_wine
6584 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6585 SelectObject(hdc, prevfont);
6586
6587 prevfont = SelectObject(hdc, hfont2);
6588 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6589 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6590 todo_wine
6591 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6592 SelectObject(hdc, prevfont);
6593
6594 DeleteDC(hdc);
6595
6596 DestroyWindow(hwnd);
6597 }
6598
6599 DeleteObject(hfont2);
6600 DestroyWindow(parent);
6601
6602 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6603
6604 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6605 100, 100, 200, 200, 0, 0, 0, NULL);
6606 ok (hwnd != 0, "Failed to create overlapped window\n");
6607
6608 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6609 0, 0, 50, 14, parent, 0, 0, NULL);
6610
6611 EnableWindow(hwnd, FALSE);
6612 flush_sequence();
6613 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6614 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6615 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6616
6617 DestroyWindow(hwnd);
6618 DestroyWindow(parent);
6619 }
6620
6621 #define ID_RADIO1 501
6622 #define ID_RADIO2 502
6623 #define ID_RADIO3 503
6624 #define ID_TEXT 504
6625
6626 static const struct message auto_radio_button_BM_CLICK[] =
6627 {
6628 { BM_CLICK, sent|wparam|lparam, 0, 0 },
6629 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6630 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6631 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6632 { WM_CTLCOLORSTATIC, sent|parent },
6633 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6634 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6635 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6636 { WM_CTLCOLORSTATIC, sent|parent },
6637 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6638 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6639 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6640 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6641 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
6642 { WM_CTLCOLORSTATIC, sent|parent },
6643 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6644 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6645 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
6646 { WM_CTLCOLORSTATIC, sent|parent },
6647 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6648 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6649 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6650 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6651 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
6652 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6653 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6654 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6655 { 0 }
6656 };
6657
6658 static const struct message auto_radio_button_VK_UP_child[] =
6659 {
6660 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
6661 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
6662 { 0 }
6663 };
6664
6665 static const struct message auto_radio_button_VK_UP_parent[] =
6666 {
6667 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
6668 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
6669 { 0 }
6670 };
6671
6672 static const struct message auto_radio_button_VK_UP_dialog[] =
6673 {
6674 { WM_GETDLGCODE, sent|parent, 0, 0 },
6675
6676 /* optional trailer seen on some windows setups */
6677 { WM_CHANGEUISTATE, sent|optional },
6678 { WM_UPDATEUISTATE, 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_CTLCOLORSTATIC, sent|parent|optional },
6697 { WM_CTLCOLORSTATIC, sent|parent|optional },
6698 { WM_CTLCOLORSTATIC, sent|parent|optional },
6699 { WM_UPDATEUISTATE, sent|optional },
6700 { WM_CTLCOLORSTATIC, sent|parent|optional },
6701 { WM_CTLCOLORSTATIC, sent|parent|optional },
6702 { WM_UPDATEUISTATE, sent|optional },
6703 { WM_CTLCOLORBTN, sent|parent|optional },
6704 { WM_CTLCOLORBTN, sent|parent|optional },
6705 { WM_UPDATEUISTATE, sent|optional },
6706 { WM_CTLCOLORSTATIC, sent|parent|optional },
6707 { WM_CTLCOLORSTATIC, sent|parent|optional },
6708 { 0 }
6709 };
6710
6711 static const struct message auto_radio_button_VK_DOWN_dialog[] =
6712 {
6713 { WM_GETDLGCODE, sent|parent, 0, 0 },
6714 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6715 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6716 { HCBT_SETFOCUS, hook },
6717 { WM_KILLFOCUS, sent, 0, 0 },
6718 { WM_CTLCOLORSTATIC, sent|parent },
6719 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
6720 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6721 { WM_SETFOCUS, sent, 0, 0 },
6722 { WM_CTLCOLORSTATIC, sent|parent },
6723 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
6724 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6725 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6726 { WM_GETDLGCODE, sent|parent, 0, 0 },
6727 { DM_GETDEFID, sent|parent, 0, 0 },
6728 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6729 { BM_CLICK, sent|wparam|lparam, 1, 0 },
6730 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6731 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6732 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6733 { WM_CTLCOLORSTATIC, sent|parent },
6734 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6735 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6736 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
6737 { WM_CTLCOLORSTATIC, sent|parent },
6738 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6739 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6740 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6741 { WM_CTLCOLORSTATIC, sent|parent },
6742 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6743 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6744 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
6745 { WM_CTLCOLORSTATIC, sent|parent },
6746 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6747 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6748 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6749 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6750 { WM_CTLCOLORSTATIC, sent|parent },
6751 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6752 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6753 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6754 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6755 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6756 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6757 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6758 { WM_PAINT, sent },
6759 { WM_CTLCOLORSTATIC, sent|parent },
6760 { 0 }
6761 };
6762
6763 static const struct message auto_radio_button_VK_DOWN_radio3[] =
6764 {
6765 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6766 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
6767 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
6768 { WM_GETDLGCODE, sent|parent, 0, 0 },
6769 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6770 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6771 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6772 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
6773 { WM_USER, sent|parent, 0, 0 },
6774 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6775 { 0 }
6776 };
6777
6778 static const struct message auto_radio_button_VK_UP_radio1[] =
6779 {
6780 { WM_GETDLGCODE, sent|parent, 0, 0 },
6781 { 0 }
6782 };
6783
6784 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
6785 {
6786 ParentMsgCheckProcA(hwnd, msg, wp, lp);
6787 return 1;
6788 }
6789
6790 static void test_autoradio_BM_CLICK(void)
6791 {
6792 HWND parent, radio1, radio2, radio3;
6793 RECT rc;
6794 MSG msg;
6795 DWORD ret;
6796
6797 subclass_button();
6798
6799 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
6800 ok(parent != 0, "failed to create parent window\n");
6801
6802 radio1 = GetDlgItem(parent, ID_RADIO1);
6803 radio2 = GetDlgItem(parent, ID_RADIO2);
6804 radio3 = GetDlgItem(parent, ID_RADIO3);
6805
6806 /* this avoids focus messages in the generated sequence */
6807 SetFocus(radio2);
6808
6809 flush_events();
6810 flush_sequence();
6811
6812 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6813 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6814 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6815 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6816 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6817 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6818
6819 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
6820
6821 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6822 ok(ret == BST_CHECKED, "got %08x\n", ret);
6823 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6824 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6825 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6826 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6827
6828 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
6829
6830 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6831 ok(ret == BST_CHECKED, "got %08x\n", ret);
6832 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6833 ok(ret == BST_CHECKED, "got %08x\n", ret);
6834 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6835 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6836
6837 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
6838
6839 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6840 ok(ret == BST_CHECKED, "got %08x\n", ret);
6841 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6842 ok(ret == BST_CHECKED, "got %08x\n", ret);
6843 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6844 ok(ret == BST_CHECKED, "got %08x\n", ret);
6845
6846 GetWindowRect(radio2, &rc);
6847 SetCursorPos(rc.left+1, rc.top+1);
6848
6849 flush_events();
6850 flush_sequence();
6851
6852 log_all_parent_messages++;
6853
6854 SendMessageA(radio2, BM_CLICK, 0, 0);
6855 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6856 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
6857
6858 log_all_parent_messages--;
6859
6860 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6861 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6862 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6863 ok(ret == BST_CHECKED, "got %08x\n", ret);
6864 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6865 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6866
6867 DestroyWindow(parent);
6868 }
6869
6870 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
6871 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
6872 {
6873 DWORD ret;
6874
6875 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6876 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6877 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6878 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6879 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6880 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6881 }
6882
6883 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
6884 {
6885 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
6886 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
6887 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
6888 }
6889
6890 static void test_autoradio_kbd_move(void)
6891 {
6892 HWND parent, radio1, radio2, radio3, hwnd;
6893 RECT rc;
6894 MSG msg;
6895 DWORD ret;
6896
6897 subclass_button();
6898
6899 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
6900 ok(parent != 0, "failed to create parent window\n");
6901
6902 radio1 = GetDlgItem(parent, ID_RADIO1);
6903 radio2 = GetDlgItem(parent, ID_RADIO2);
6904 radio3 = GetDlgItem(parent, ID_RADIO3);
6905
6906 flush_events();
6907 flush_sequence();
6908
6909 test_radio(radio1, 0, radio2, 0, radio3, 0);
6910 set_radio(radio1, 1, radio2, 1, radio3, 1);
6911 test_radio(radio1, 1, radio2, 1, radio3, 1);
6912
6913 SetFocus(radio3);
6914
6915 flush_events();
6916 flush_sequence();
6917
6918 log_all_parent_messages++;
6919
6920 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
6921 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
6922 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6923 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
6924
6925 test_radio(radio1, 1, radio2, 1, radio3, 1);
6926
6927 flush_events();
6928 flush_sequence();
6929
6930 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
6931 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
6932 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6933 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
6934
6935 test_radio(radio1, 1, radio2, 1, radio3, 1);
6936
6937 SetFocus(radio3);
6938 GetWindowRect(radio3, &rc);
6939
6940 flush_events();
6941 flush_sequence();
6942
6943 msg.hwnd = parent;
6944 msg.message = WM_KEYDOWN;
6945 msg.wParam = VK_UP;
6946 msg.lParam = 0;
6947 msg.pt.x = rc.left + 1;
6948 msg.pt.y = rc.top + 1;
6949 ret = IsDialogMessageA(parent, &msg);
6950 ok(ret, "IsDialogMessage should return TRUE\n");
6951 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6952 if (0) /* actual message sequence is different on every run in some Windows setups */
6953 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
6954 /* what really matters is that nothing has changed */
6955 test_radio(radio1, 1, radio2, 1, radio3, 1);
6956
6957 set_radio(radio1, 0, radio2, 1, radio3, 1);
6958 test_radio(radio1, 0, radio2, 1, radio3, 1);
6959
6960 flush_events();
6961 flush_sequence();
6962
6963 ret = IsDialogMessageA(parent, &msg);
6964 ok(ret, "IsDialogMessage should return TRUE\n");
6965 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6966 if (0) /* actual message sequence is different on every run in some Windows setups */
6967 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
6968 /* what really matters is that nothing has changed */
6969 test_radio(radio1, 0, radio2, 1, radio3, 1);
6970
6971 /* switch from radio3 ro radio1 */
6972 SetFocus(radio3);
6973 GetWindowRect(radio3, &rc);
6974
6975 flush_events();
6976 flush_sequence();
6977
6978 msg.hwnd = parent;
6979 msg.message = WM_KEYDOWN;
6980 msg.wParam = VK_DOWN;
6981 msg.lParam = 0;
6982 msg.pt.x = rc.left + 1;
6983 msg.pt.y = rc.top + 1;
6984 ret = IsDialogMessageA(parent, &msg);
6985 ok(ret, "IsDialogMessage should return TRUE\n");
6986 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6987 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
6988
6989 test_radio(radio1, 1, radio2, 0, radio3, 0);
6990
6991 hwnd = GetFocus();
6992 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
6993 GetWindowRect(radio1, &rc);
6994
6995 msg.hwnd = parent;
6996 msg.message = WM_KEYDOWN;
6997 msg.wParam = VK_DOWN;
6998 msg.lParam = 0;
6999 msg.pt.x = rc.left + 1;
7000 msg.pt.y = rc.top + 1;
7001 ret = IsDialogMessageA(parent, &msg);
7002 ok(ret, "IsDialogMessage should return TRUE\n");
7003 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7004 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7005
7006 test_radio(radio1, 1, radio2, 0, radio3, 0);
7007
7008 hwnd = GetFocus();
7009 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7010
7011 flush_events();
7012 flush_sequence();
7013
7014 msg.hwnd = parent;
7015 msg.message = WM_KEYDOWN;
7016 msg.wParam = VK_UP;
7017 msg.lParam = 0;
7018 msg.pt.x = rc.left + 1;
7019 msg.pt.y = rc.top + 1;
7020 ret = IsDialogMessageA(parent, &msg);
7021 ok(ret, "IsDialogMessage should return TRUE\n");
7022 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7023 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7024
7025 test_radio(radio1, 1, radio2, 0, radio3, 0);
7026
7027 hwnd = GetFocus();
7028 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7029
7030 flush_events();
7031 flush_sequence();
7032
7033 msg.hwnd = parent;
7034 msg.message = WM_KEYDOWN;
7035 msg.wParam = VK_UP;
7036 msg.lParam = 0;
7037 msg.pt.x = rc.left + 1;
7038 msg.pt.y = rc.top + 1;
7039 ret = IsDialogMessageA(parent, &msg);
7040 ok(ret, "IsDialogMessage should return TRUE\n");
7041 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7042 if (0) /* actual message sequence is different on every run in some Windows setups */
7043 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7044 /* what really matters is that nothing has changed */
7045 test_radio(radio1, 1, radio2, 0, radio3, 0);
7046
7047 log_all_parent_messages--;
7048
7049 DestroyWindow(parent);
7050 }
7051
7052 /****************** static message test *************************/
7053 static const struct message WmSetFontStaticSeq2[] =
7054 {
7055 { WM_SETFONT, sent },
7056 { WM_PAINT, sent|defwinproc|optional },
7057 { WM_ERASEBKGND, sent|defwinproc|optional },
7058 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7059 { 0 }
7060 };
7061
7062 static WNDPROC old_static_proc;
7063
7064 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7065 {
7066 static LONG defwndproc_counter = 0;
7067 LRESULT ret;
7068 struct recvd_message msg;
7069
7070 if (ignore_message( message )) return 0;
7071
7072 msg.hwnd = hwnd;
7073 msg.message = message;
7074 msg.flags = sent|wparam|lparam;
7075 if (defwndproc_counter) msg.flags |= defwinproc;
7076 msg.wParam = wParam;
7077 msg.lParam = lParam;
7078 msg.descr = "static";
7079 add_message(&msg);
7080
7081 defwndproc_counter++;
7082 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7083 defwndproc_counter--;
7084
7085 return ret;
7086 }
7087
7088 static void subclass_static(void)
7089 {
7090 WNDCLASSA cls;
7091
7092 if (!GetClassInfoA(0, "static", &cls)) assert(0);
7093
7094 old_static_proc = cls.lpfnWndProc;
7095
7096 cls.hInstance = GetModuleHandleA(NULL);
7097 cls.lpfnWndProc = static_hook_proc;
7098 cls.lpszClassName = "my_static_class";
7099 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7100 if (!RegisterClassA(&cls)) assert(0);
7101 }
7102
7103 static void test_static_messages(void)
7104 {
7105 /* FIXME: make as comprehensive as the button message test */
7106 static const struct
7107 {
7108 DWORD style;
7109 DWORD dlg_code;
7110 const struct message *setfont;
7111 } static_ctrl[] = {
7112 { SS_LEFT, DLGC_STATIC,
7113 WmSetFontStaticSeq2 }
7114 };
7115 unsigned int i;
7116 HWND hwnd;
7117 DWORD dlg_code;
7118
7119 subclass_static();
7120
7121 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
7122 {
7123 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7124 0, 0, 50, 14, 0, 0, 0, NULL);
7125 ok(hwnd != 0, "Failed to create static window\n");
7126
7127 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7128 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7129
7130 ShowWindow(hwnd, SW_SHOW);
7131 UpdateWindow(hwnd);
7132 SetFocus(0);
7133 flush_sequence();
7134
7135 trace("static style %08x\n", static_ctrl[i].style);
7136 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7137 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7138
7139 DestroyWindow(hwnd);
7140 }
7141 }
7142
7143 /****************** ComboBox message test *************************/
7144 #define ID_COMBOBOX 0x000f
7145
7146 static const struct message WmKeyDownComboSeq[] =
7147 {
7148 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7149 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7150 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7151 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7152 { WM_CTLCOLOREDIT, sent|parent },
7153 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7154 { 0 }
7155 };
7156
7157 static const struct message WmSetPosComboSeq[] =
7158 {
7159 { WM_WINDOWPOSCHANGING, sent },
7160 { WM_NCCALCSIZE, sent|wparam, TRUE },
7161 { WM_CHILDACTIVATE, sent },
7162 { WM_WINDOWPOSCHANGED, sent },
7163 { WM_MOVE, sent|defwinproc },
7164 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7165 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7166 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7167 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7168 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7169 { 0 }
7170 };
7171
7172 static const struct message WMSetFocusComboBoxSeq[] =
7173 {
7174 { WM_SETFOCUS, sent },
7175 { WM_KILLFOCUS, sent|parent },
7176 { WM_SETFOCUS, sent },
7177 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7178 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7179 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7180 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7181 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7182 { 0 }
7183 };
7184
7185 static const struct message SetFocusButtonSeq[] =
7186 {
7187 { WM_KILLFOCUS, sent },
7188 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7189 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7190 { WM_LBUTTONUP, sent|defwinproc },
7191 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7192 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7193 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7194 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7195 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7196 { WM_CTLCOLORBTN, sent|parent },
7197 { 0 }
7198 };
7199
7200 static const struct message SetFocusComboBoxSeq[] =
7201 {
7202 { WM_CTLCOLORBTN, sent|parent },
7203 { WM_SETFOCUS, sent },
7204 { WM_KILLFOCUS, sent|defwinproc },
7205 { WM_SETFOCUS, sent },
7206 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7207 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7208 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7209 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7210 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7211 { 0 }
7212 };
7213
7214 static const struct message SetFocusButtonSeq2[] =
7215 {
7216 { WM_KILLFOCUS, sent },
7217 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7218 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7219 { WM_LBUTTONUP, sent|defwinproc },
7220 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7221 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7222 { WM_CTLCOLOREDIT, sent|defwinproc },
7223 { WM_CTLCOLOREDIT, sent|parent },
7224 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7225 { WM_CTLCOLORBTN, sent|parent },
7226 { 0 }
7227 };
7228
7229 static WNDPROC old_combobox_proc, edit_window_proc;
7230
7231 static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7232 {
7233 static LONG defwndproc_counter = 0;
7234 LRESULT ret;
7235 struct recvd_message msg;
7236
7237 /* do not log painting messages */
7238 if (message != WM_PAINT &&
7239 message != WM_NCPAINT &&
7240 message != WM_SYNCPAINT &&
7241 message != WM_ERASEBKGND &&
7242 message != WM_NCHITTEST &&
7243 message != WM_GETTEXT &&
7244 !ignore_message( message ))
7245 {
7246 msg.hwnd = hwnd;
7247 msg.message = message;
7248 msg.flags = sent|wparam|lparam;
7249 if (defwndproc_counter) msg.flags |= defwinproc;
7250 msg.wParam = wParam;
7251 msg.lParam = lParam;
7252 msg.descr = "combo";
7253 add_message(&msg);
7254 }
7255
7256 defwndproc_counter++;
7257 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7258 defwndproc_counter--;
7259
7260 return ret;
7261 }
7262
7263 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7264 {
7265 static LONG defwndproc_counter = 0;
7266 LRESULT ret;
7267 struct recvd_message msg;
7268
7269 /* do not log painting messages */
7270 if (message != WM_PAINT &&
7271 message != WM_NCPAINT &&
7272 message != WM_SYNCPAINT &&
7273 message != WM_ERASEBKGND &&
7274 message != WM_NCHITTEST &&
7275 message != WM_GETTEXT &&
7276 !ignore_message( message ))
7277 {
7278 msg.hwnd = hwnd;
7279 msg.message = message;
7280 msg.flags = sent|wparam|lparam;
7281 if (defwndproc_counter) msg.flags |= defwinproc;
7282 msg.wParam = wParam;
7283 msg.lParam = lParam;
7284 msg.descr = "combo";
7285 add_message(&msg);
7286 }
7287
7288 defwndproc_counter++;
7289 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7290 defwndproc_counter--;
7291
7292 return ret;
7293 }
7294
7295 static void subclass_combobox(void)
7296 {
7297 WNDCLASSA cls;
7298
7299 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7300
7301 old_combobox_proc = cls.lpfnWndProc;
7302
7303 cls.hInstance = GetModuleHandleA(NULL);
7304 cls.lpfnWndProc = combobox_hook_proc;
7305 cls.lpszClassName = "my_combobox_class";
7306 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7307 if (!RegisterClassA(&cls)) assert(0);
7308 }
7309
7310 static void test_combobox_messages(void)
7311 {
7312 HWND parent, combo, button, edit;
7313 LRESULT ret;
7314 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
7315 COMBOBOXINFO cbInfo;
7316 BOOL res;
7317
7318 subclass_combobox();
7319
7320 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7321 100, 100, 200, 200, 0, 0, 0, NULL);
7322 ok(parent != 0, "Failed to create parent window\n");
7323 flush_sequence();
7324
7325 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7326 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7327 ok(combo != 0, "Failed to create combobox window\n");
7328
7329 UpdateWindow(combo);
7330
7331 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7332 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7333
7334 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7335 ok(ret == 0, "expected 0, got %ld\n", ret);
7336 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7337 ok(ret == 1, "expected 1, got %ld\n", ret);
7338 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7339 ok(ret == 2, "expected 2, got %ld\n", ret);
7340
7341 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7342 SetFocus(combo);
7343 flush_sequence();
7344
7345 log_all_parent_messages++;
7346 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7347 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7348 log_all_parent_messages--;
7349 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7350
7351 flush_sequence();
7352 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7353 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7354
7355 DestroyWindow(combo);
7356 DestroyWindow(parent);
7357
7358 /* Start again. Test combobox text selection when getting and losing focus */
7359 pGetComboBoxInfo = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
7360 if (!pGetComboBoxInfo)
7361 {
7362 win_skip("GetComboBoxInfo is not available\n");
7363 return;
7364 }
7365
7366 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7367 10, 10, 300, 300, NULL, NULL, NULL, NULL);
7368 ok(parent != 0, "Failed to create parent window\n");
7369
7370 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7371 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7372 ok(combo != 0, "Failed to create combobox window\n");
7373
7374 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7375 SetLastError(0xdeadbeef);
7376 res = pGetComboBoxInfo(combo, &cbInfo);
7377 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7378 edit = cbInfo.hwndItem;
7379
7380 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc);
7381
7382 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7383 5, 50, 100, 20, parent, NULL,
7384 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7385 ok(button != 0, "Failed to create button window\n");
7386
7387 flush_sequence();
7388 log_all_parent_messages++;
7389 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7390 log_all_parent_messages--;
7391 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7392
7393 flush_sequence();
7394 log_all_parent_messages++;
7395 SetFocus(button);
7396 log_all_parent_messages--;
7397 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7398
7399 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7400
7401 flush_sequence();
7402 log_all_parent_messages++;
7403 SetFocus(combo);
7404 log_all_parent_messages--;
7405 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7406
7407 flush_sequence();
7408 log_all_parent_messages++;
7409 SetFocus(button);
7410 log_all_parent_messages--;
7411 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7412
7413 DestroyWindow(button);
7414 DestroyWindow(combo);
7415 DestroyWindow(parent);
7416 }
7417
7418 /****************** WM_IME_KEYDOWN message test *******************/
7419
7420 static const struct message WmImeKeydownMsgSeq_0[] =
7421 {
7422 { WM_IME_KEYDOWN, wparam, VK_RETURN },
7423 { WM_CHAR, wparam, 'A' },
7424 { 0 }
7425 };
7426
7427 static const struct message WmImeKeydownMsgSeq_1[] =
7428 {
7429 { WM_KEYDOWN, optional|wparam, VK_RETURN },
7430 { WM_CHAR, optional|wparam, VK_RETURN },
7431 { 0 }
7432 };
7433
7434 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7435 {
7436 struct recvd_message msg;
7437
7438 msg.hwnd = hwnd;
7439 msg.message = message;
7440 msg.flags = wparam|lparam;
7441 msg.wParam = wParam;
7442 msg.lParam = lParam;
7443 msg.descr = "wmime_keydown";
7444 add_message(&msg);
7445
7446 return DefWindowProcA(hwnd, message, wParam, lParam);
7447 }
7448
7449 static void register_wmime_keydown_class(void)
7450 {
7451 WNDCLASSA cls;
7452
7453 ZeroMemory(&cls, sizeof(WNDCLASSA));
7454 cls.lpfnWndProc = wmime_keydown_procA;
7455 cls.hInstance = GetModuleHandleA(0);
7456 cls.lpszClassName = "wmime_keydown_class";
7457 if (!RegisterClassA(&cls)) assert(0);
7458 }
7459
7460 static void test_wmime_keydown_message(void)
7461 {
7462 HWND hwnd;
7463 MSG msg;
7464
7465 trace("Message sequences by WM_IME_KEYDOWN\n");
7466
7467 register_wmime_keydown_class();
7468 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7469 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7470 NULL, NULL, 0);
7471 flush_events();
7472 flush_sequence();
7473
7474 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7475 SendMessageA(hwnd, WM_CHAR, 'A', 1);
7476 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7477
7478 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7479 {
7480 TranslateMessage(&msg);
7481 DispatchMessageA(&msg);
7482 }
7483 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7484
7485 DestroyWindow(hwnd);
7486 }
7487
7488 /************* painting message test ********************/
7489
7490 void dump_region(HRGN hrgn)
7491 {
7492 DWORD i, size;
7493 RGNDATA *data = NULL;
7494 RECT *rect;
7495
7496 if (!hrgn)
7497 {
7498 printf( "null region\n" );
7499 return;
7500 }
7501 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7502 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7503 GetRegionData( hrgn, size, data );
7504 printf("%d rects:", data->rdh.nCount );
7505 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7506 printf( " %s", wine_dbgstr_rect( rect ));
7507 printf("\n");
7508 HeapFree( GetProcessHeap(), 0, data );
7509 }
7510
7511 static void check_update_rgn( HWND hwnd, HRGN hrgn )
7512 {
7513 INT ret;
7514 RECT r1, r2;
7515 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7516 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7517
7518 ret = GetUpdateRgn( hwnd, update, FALSE );
7519 ok( ret != ERROR, "GetUpdateRgn failed\n" );
7520 if (ret == NULLREGION)
7521 {
7522 ok( !hrgn, "Update region shouldn't be empty\n" );
7523 }
7524 else
7525 {
7526 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7527 {
7528 ok( 0, "Regions are different\n" );
7529 if (winetest_debug > 0)
7530 {
7531 printf( "Update region: " );
7532 dump_region( update );
7533 printf( "Wanted region: " );
7534 dump_region( hrgn );
7535 }
7536 }
7537 }
7538 GetRgnBox( update, &r1 );
7539 GetUpdateRect( hwnd, &r2, FALSE );
7540 ok( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", wine_dbgstr_rect( &r1 ),
7541 wine_dbgstr_rect( &r2 ));
7542
7543 DeleteObject( tmp );
7544 DeleteObject( update );
7545 }
7546
7547 static const struct message WmInvalidateRgn[] = {
7548 { WM_NCPAINT, sent },
7549 { WM_GETTEXT, sent|defwinproc|optional },
7550 { 0 }
7551 };
7552
7553 static const struct message WmGetUpdateRect[] = {
7554 { WM_NCPAINT, sent },
7555 { WM_GETTEXT, sent|defwinproc|optional },
7556 { WM_PAINT, sent },
7557 { 0 }
7558 };
7559
7560 static const struct message WmInvalidateFull[] = {
7561 { WM_NCPAINT, sent|wparam, 1 },
7562 { WM_GETTEXT, sent|defwinproc|optional },
7563 { 0 }
7564 };
7565
7566 static const struct message WmInvalidateErase[] = {
7567 { WM_NCPAINT, sent|wparam, 1 },
7568 { WM_GETTEXT, sent|defwinproc|optional },
7569 { WM_ERASEBKGND, sent },
7570 { 0 }
7571 };
7572
7573 static const struct message WmInvalidatePaint[] = {
7574 { WM_PAINT, sent },
7575 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7576 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7577 { 0 }
7578 };
7579
7580 static const struct message WmInvalidateErasePaint[] = {
7581 { WM_PAINT, sent },
7582 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7583 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7584 { WM_ERASEBKGND, sent|beginpaint|optional },
7585 { 0 }
7586 };
7587
7588 static const struct message WmInvalidateErasePaint2[] = {
7589 { WM_PAINT, sent },
7590 { WM_NCPAINT, sent|beginpaint },
7591 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7592 { WM_ERASEBKGND, sent|beginpaint|optional },
7593 { 0 }
7594 };
7595
7596 static const struct message WmErase[] = {
7597 { WM_ERASEBKGND, sent },
7598 { 0 }
7599 };
7600
7601 static const struct message WmPaint[] = {
7602 { WM_PAINT, sent },
7603 { 0 }
7604 };
7605
7606 static const struct message WmParentOnlyPaint[] = {
7607 { WM_PAINT, sent|parent },
7608 { 0 }
7609 };
7610
7611 static const struct message WmInvalidateParent[] = {
7612 { WM_NCPAINT, sent|parent },
7613 { WM_GETTEXT, sent|defwinproc|parent|optional },
7614 { WM_ERASEBKGND, sent|parent },
7615 { 0 }
7616 };
7617
7618 static const struct message WmInvalidateParentChild[] = {
7619 { WM_NCPAINT, sent|parent },
7620 { WM_GETTEXT, sent|defwinproc|parent|optional },
7621 { WM_ERASEBKGND, sent|parent },
7622 { WM_NCPAINT, sent },
7623 { WM_GETTEXT, sent|defwinproc|optional },
7624 { WM_ERASEBKGND, sent },
7625 { 0 }
7626 };
7627
7628 static const struct message WmInvalidateParentChild2[] = {
7629 { WM_ERASEBKGND, sent|parent },
7630 { WM_NCPAINT, sent },
7631 { WM_GETTEXT, sent|defwinproc|optional },
7632 { WM_ERASEBKGND, sent },
7633 { 0 }
7634 };
7635
7636 static const struct message WmParentPaint[] = {
7637 { WM_PAINT, sent|parent },
7638 { WM_PAINT, sent },
7639 { 0 }
7640 };
7641
7642 static const struct message WmParentPaintNc[] = {
7643 { WM_PAINT, sent|parent },
7644 { WM_PAINT, sent },
7645 { WM_NCPAINT, sent|beginpaint },
7646 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7647 { WM_ERASEBKGND, sent|beginpaint|optional },
7648 { 0 }
7649 };
7650
7651 static const struct message WmChildPaintNc[] = {
7652 { WM_PAINT, sent },
7653 { WM_NCPAINT, sent|beginpaint },
7654 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7655 { WM_ERASEBKGND, sent|beginpaint|optional },
7656 { 0 }
7657 };
7658
7659 static const struct message WmParentErasePaint[] = {
7660 { WM_PAINT, sent|parent },
7661 { WM_NCPAINT, sent|parent|beginpaint },
7662 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7663 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7664 { WM_PAINT, sent },
7665 { WM_NCPAINT, sent|beginpaint },
7666 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7667 { WM_ERASEBKGND, sent|beginpaint|optional },
7668 { 0 }
7669 };
7670
7671 static const struct message WmParentOnlyNcPaint[] = {
7672 { WM_PAINT, sent|parent },
7673 { WM_NCPAINT, sent|parent|beginpaint },
7674 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7675 { 0 }
7676 };
7677
7678 static const struct message WmSetParentStyle[] = {
7679 { WM_STYLECHANGING, sent|parent },
7680 { WM_STYLECHANGED, sent|parent },
7681 { 0 }
7682 };
7683
7684 static void test_paint_messages(void)
7685 {
7686 BOOL ret;
7687 RECT rect, rect2;
7688 POINT pt;
7689 MSG msg;
7690 HWND hparent, hchild;
7691 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7692 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7693 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7694 100, 100, 200, 200, 0, 0, 0, NULL);
7695 ok (hwnd != 0, "Failed to create overlapped window\n");
7696
7697 ShowWindow( hwnd, SW_SHOW );
7698 UpdateWindow( hwnd );
7699 flush_events();
7700 flush_sequence();
7701
7702 check_update_rgn( hwnd, 0 );
7703 SetRectRgn( hrgn, 10, 10, 20, 20 );
7704 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7705 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7706 check_update_rgn( hwnd, hrgn );
7707 SetRectRgn( hrgn2, 20, 20, 30, 30 );
7708 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7709 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7710 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7711 check_update_rgn( hwnd, hrgn );
7712 /* validate everything */
7713 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7714 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7715 check_update_rgn( hwnd, 0 );
7716
7717 /* test empty region */
7718 SetRectRgn( hrgn, 10, 10, 10, 15 );
7719 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7720 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7721 check_update_rgn( hwnd, 0 );
7722 /* test empty rect */
7723 SetRect( &rect, 10, 10, 10, 15 );
7724 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7725 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7726 check_update_rgn( hwnd, 0 );
7727
7728 /* flush pending messages */
7729 flush_events();
7730 flush_sequence();
7731
7732 GetClientRect( hwnd, &rect );
7733 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7734 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7735 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7736 */
7737 trace("testing InvalidateRect(0, NULL, FALSE)\n");
7738 SetRectEmpty( &rect );
7739 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
7740 check_update_rgn( hwnd, hrgn );
7741 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7742 flush_events();
7743 ok_sequence( WmPaint, "Paint", FALSE );
7744 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7745 check_update_rgn( hwnd, 0 );
7746
7747 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
7748 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7749 */
7750 trace("testing ValidateRect(0, NULL)\n");
7751 SetRectEmpty( &rect );
7752 if (ValidateRect(0, &rect) && /* not supported on Win9x */
7753 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
7754 {
7755 check_update_rgn( hwnd, hrgn );
7756 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7757 flush_events();
7758 ok_sequence( WmPaint, "Paint", FALSE );
7759 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7760 check_update_rgn( hwnd, 0 );
7761 }
7762
7763 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
7764 SetLastError(0xdeadbeef);
7765 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
7766 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
7767 "wrong error code %d\n", GetLastError());
7768 check_update_rgn( hwnd, 0 );
7769 flush_events();
7770 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7771
7772 trace("testing ValidateRgn(0, NULL)\n");
7773 SetLastError(0xdeadbeef);
7774 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
7775 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7776 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7777 "wrong error code %d\n", GetLastError());
7778 check_update_rgn( hwnd, 0 );
7779 flush_events();
7780 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7781
7782 trace("testing UpdateWindow(NULL)\n");
7783 SetLastError(0xdeadbeef);
7784 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
7785 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7786 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7787 "wrong error code %d\n", GetLastError());
7788 check_update_rgn( hwnd, 0 );
7789 flush_events();
7790 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7791
7792 /* now with frame */
7793 SetRectRgn( hrgn, -5, -5, 20, 20 );
7794
7795 /* flush pending messages */
7796 flush_events();
7797 flush_sequence();
7798 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7799 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7800
7801 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
7802 check_update_rgn( hwnd, hrgn );
7803
7804 flush_sequence();
7805 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7806 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7807
7808 flush_sequence();
7809 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7810 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
7811
7812 GetClientRect( hwnd, &rect );
7813 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7814 check_update_rgn( hwnd, hrgn );
7815
7816 flush_sequence();
7817 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
7818 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7819
7820 flush_sequence();
7821 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
7822 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
7823 check_update_rgn( hwnd, 0 );
7824
7825 flush_sequence();
7826 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
7827 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
7828 check_update_rgn( hwnd, 0 );
7829
7830 flush_sequence();
7831 SetRectRgn( hrgn, 0, 0, 100, 100 );
7832 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7833 SetRectRgn( hrgn, 0, 0, 50, 100 );
7834 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
7835 SetRectRgn( hrgn, 50, 0, 100, 100 );
7836 check_update_rgn( hwnd, hrgn );
7837 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7838 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
7839 check_update_rgn( hwnd, 0 );
7840
7841 flush_sequence();
7842 SetRectRgn( hrgn, 0, 0, 100, 100 );
7843 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7844 SetRectRgn( hrgn, 0, 0, 100, 50 );
7845 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7846 ok_sequence( WmErase, "Erase", FALSE );
7847 SetRectRgn( hrgn, 0, 50, 100, 100 );
7848 check_update_rgn( hwnd, hrgn );
7849
7850 flush_sequence();
7851 SetRectRgn( hrgn, 0, 0, 100, 100 );
7852 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7853 SetRectRgn( hrgn, 0, 0, 50, 50 );
7854 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
7855 ok_sequence( WmPaint, "Paint", FALSE );
7856
7857 flush_sequence();
7858 SetRectRgn( hrgn, -4, -4, -2, -2 );
7859 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7860 SetRectRgn( hrgn, -200, -200, -198, -198 );
7861 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
7862 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7863
7864 flush_sequence();
7865 SetRectRgn( hrgn, -4, -4, -2, -2 );
7866 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7867 SetRectRgn( hrgn, -4, -4, -3, -3 );
7868 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
7869 SetRectRgn( hrgn, 0, 0, 1, 1 );
7870 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
7871 ok_sequence( WmPaint, "Paint", FALSE );
7872
7873 flush_sequence();
7874 SetRectRgn( hrgn, -4, -4, -1, -1 );
7875 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7876 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
7877 /* make sure no WM_PAINT was generated */
7878 flush_events();
7879 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7880
7881 flush_sequence();
7882 SetRectRgn( hrgn, -4, -4, -1, -1 );
7883 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7884 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
7885 {
7886 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
7887 {
7888 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
7889 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
7890 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
7891 ret = GetUpdateRect( hwnd, &rect, FALSE );
7892 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
7893 /* this will send WM_NCPAINT and validate the non client area */
7894 ret = GetUpdateRect( hwnd, &rect, TRUE );
7895 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
7896 }
7897 DispatchMessageA( &msg );
7898 }
7899 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
7900
7901 DestroyWindow( hwnd );
7902
7903 /* now test with a child window */
7904
7905 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
7906 100, 100, 200, 200, 0, 0, 0, NULL);
7907 ok (hparent != 0, "Failed to create parent window\n");
7908
7909 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
7910 10, 10, 100, 100, hparent, 0, 0, NULL);
7911 ok (hchild != 0, "Failed to create child window\n");
7912
7913 ShowWindow( hparent, SW_SHOW );
7914 UpdateWindow( hparent );
7915 UpdateWindow( hchild );
7916 flush_events();
7917 flush_sequence();
7918 log_all_parent_messages++;
7919
7920 SetRect( &rect, 0, 0, 50, 50 );
7921 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7922 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7923 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
7924
7925 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7926 pt.x = pt.y = 0;
7927 MapWindowPoints( hchild, hparent, &pt, 1 );
7928 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
7929 check_update_rgn( hchild, hrgn );
7930 SetRectRgn( hrgn, 0, 0, 50, 50 );
7931 check_update_rgn( hparent, hrgn );
7932 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7933 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
7934 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7935 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7936
7937 flush_events();
7938 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
7939
7940 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7941 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7942 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
7943 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7944 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7945
7946 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7947 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7948 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
7949
7950 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
7951 flush_sequence();
7952 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7953 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7954 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
7955
7956 /* flush all paint messages */
7957 flush_events();
7958 flush_sequence();
7959
7960 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
7961 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7962 SetRectRgn( hrgn, 0, 0, 50, 50 );
7963 check_update_rgn( hparent, hrgn );
7964 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7965 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7966 SetRectRgn( hrgn, 0, 0, 50, 50 );
7967 check_update_rgn( hparent, hrgn );
7968
7969 /* flush all paint messages */
7970 flush_events();
7971 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
7972 flush_sequence();
7973
7974 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
7975 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7976 SetRectRgn( hrgn, 0, 0, 50, 50 );
7977 check_update_rgn( hparent, hrgn );
7978 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7979 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7980 SetRectRgn( hrgn2, 10, 10, 50, 50 );
7981 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
7982 check_update_rgn( hparent, hrgn );
7983 /* flush all paint messages */
7984 flush_events();
7985 flush_sequence();
7986
7987 /* same as above but parent gets completely validated */
7988 SetRect( &rect, 20, 20, 30, 30 );
7989 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7990 SetRectRgn( hrgn, 20, 20, 30, 30 );
7991 check_update_rgn( hparent, hrgn );
7992 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7993 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7994 check_update_rgn( hparent, 0 ); /* no update region */
7995 flush_events();
7996 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
7997
7998 /* make sure RDW_VALIDATE on child doesn't have the same effect */
7999 flush_sequence();
8000 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8001 SetRectRgn( hrgn, 20, 20, 30, 30 );
8002 check_update_rgn( hparent, hrgn );
8003 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8004 SetRectRgn( hrgn, 20, 20, 30, 30 );
8005 check_update_rgn( hparent, hrgn );
8006
8007 /* same as above but normal WM_PAINT doesn't validate parent */
8008 flush_sequence();
8009 SetRect( &rect, 20, 20, 30, 30 );
8010 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8011 SetRectRgn( hrgn, 20, 20, 30, 30 );
8012 check_update_rgn( hparent, hrgn );
8013 /* no WM_PAINT in child while parent still pending */
8014 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8015 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8016 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8017 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8018
8019 flush_sequence();
8020 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8021 /* no WM_PAINT in child while parent still pending */
8022 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8023 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8024 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8025 /* now that parent is valid child should get WM_PAINT */
8026 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8027 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8028 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8029 ok_sequence( WmEmptySeq, "No other message", FALSE );
8030
8031 /* same thing with WS_CLIPCHILDREN in parent */
8032 flush_sequence();
8033 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8034 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8035 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8036 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8037 ok_sequence( WmEmptySeq, "No message", FALSE );
8038 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8039 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8040
8041 flush_sequence();
8042 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8043 SetRectRgn( hrgn, 20, 20, 30, 30 );
8044 check_update_rgn( hparent, hrgn );
8045 /* no WM_PAINT in child while parent still pending */
8046 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8047 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8048 /* WM_PAINT in parent first */
8049 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8050 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8051
8052 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8053 flush_sequence();
8054 SetRect( &rect, 0, 0, 30, 30 );
8055 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8056 SetRectRgn( hrgn, 0, 0, 30, 30 );
8057 check_update_rgn( hparent, hrgn );
8058 flush_events();
8059 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8060
8061 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8062 flush_sequence();
8063 SetRect( &rect, -10, 0, 30, 30 );
8064 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8065 SetRect( &rect, 0, 0, 20, 20 );
8066 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8067 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8068 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8069
8070 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8071 flush_sequence();
8072 SetRect( &rect, -10, 0, 30, 30 );
8073 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8074 SetRect( &rect, 0, 0, 100, 100 );
8075 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8076 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8077 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8078 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8079 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8080
8081 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8082 flush_sequence();
8083 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8084 GetClientRect( hparent, &rect );
8085 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8086 check_update_rgn( hparent, hrgn );
8087 flush_events();
8088
8089 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8090 GetClientRect( hparent, &rect );
8091 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8092 check_update_rgn( hparent, hrgn );
8093 flush_events();
8094
8095 /* test RDW_INTERNALPAINT behavior */
8096
8097 flush_sequence();
8098 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8099 flush_events();
8100 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8101
8102 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8103 flush_events();
8104 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8105
8106 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8107 flush_events();
8108 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8109
8110 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8111 UpdateWindow( hparent );
8112 flush_events();
8113 flush_sequence();
8114 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8115 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8116 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8117 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8118 flush_events();
8119 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8120
8121 UpdateWindow( hparent );
8122 flush_events();
8123 flush_sequence();
8124 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8125 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8126 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8127 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8128 flush_events();
8129 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8130
8131 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8132 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8133 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8134 flush_events();
8135 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8136
8137 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8138 UpdateWindow( hparent );
8139 flush_events();
8140 flush_sequence();
8141 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8142 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8143 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8144 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8145 flush_events();
8146 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8147
8148 UpdateWindow( hparent );
8149 flush_events();
8150 flush_sequence();
8151 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8152 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8153 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8154 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8155 flush_events();
8156 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8157
8158 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8159 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8160
8161 UpdateWindow( hparent );
8162 flush_events();
8163 flush_sequence();
8164 trace("testing SetWindowPos(-10000, -10000) on child\n");
8165 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8166 check_update_rgn( hchild, 0 );
8167 flush_events();
8168
8169 #if 0 /* this one doesn't pass under Wine yet */
8170 UpdateWindow( hparent );
8171 flush_events();
8172 flush_sequence();
8173 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8174 ShowWindow( hchild, SW_MINIMIZE );
8175 check_update_rgn( hchild, 0 );
8176 flush_events();
8177 #endif
8178
8179 UpdateWindow( hparent );
8180 flush_events();
8181 flush_sequence();
8182 trace("testing SetWindowPos(-10000, -10000) on parent\n");
8183 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8184 check_update_rgn( hparent, 0 );
8185 flush_events();
8186
8187 log_all_parent_messages--;
8188 DestroyWindow( hparent );
8189 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8190
8191 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8192
8193 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8194 100, 100, 200, 200, 0, 0, 0, NULL);
8195 ok (hparent != 0, "Failed to create parent window\n");
8196
8197 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8198 10, 10, 100, 100, hparent, 0, 0, NULL);
8199 ok (hchild != 0, "Failed to create child window\n");
8200
8201 ShowWindow( hparent, SW_SHOW );
8202 UpdateWindow( hparent );
8203 UpdateWindow( hchild );
8204 flush_events();
8205 flush_sequence();
8206
8207 /* moving child outside of parent boundaries changes update region */
8208 SetRect( &rect, 0, 0, 40, 40 );
8209 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8210 SetRectRgn( hrgn, 0, 0, 40, 40 );
8211 check_update_rgn( hchild, hrgn );
8212 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8213 SetRectRgn( hrgn, 10, 0, 40, 40 );
8214 check_update_rgn( hchild, hrgn );
8215 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8216 SetRectRgn( hrgn, 10, 10, 40, 40 );
8217 check_update_rgn( hchild, hrgn );
8218
8219 /* moving parent off-screen does too */
8220 SetRect( &rect, 0, 0, 100, 100 );
8221 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8222 SetRectRgn( hrgn, 0, 0, 100, 100 );
8223 check_update_rgn( hparent, hrgn );
8224 SetRectRgn( hrgn, 10, 10, 40, 40 );
8225 check_update_rgn( hchild, hrgn );
8226 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8227 GetUpdateRect( hparent, &rect2, FALSE );
8228 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8229 {
8230 rect.left += 20;
8231 rect.top += 20;
8232 }
8233 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8234 check_update_rgn( hparent, hrgn );
8235 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8236 check_update_rgn( hchild, hrgn );
8237
8238 /* invalidated region is cropped by the parent rects */
8239 SetRect( &rect, 0, 0, 50, 50 );
8240 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8241 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8242 check_update_rgn( hchild, hrgn );
8243
8244 DestroyWindow( hparent );
8245 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8246 flush_sequence();
8247
8248 DeleteObject( hrgn );
8249 DeleteObject( hrgn2 );
8250 }
8251
8252 struct wnd_event
8253 {
8254 HWND hwnd;
8255 HANDLE grand_child;
8256 HANDLE start_event;
8257 HANDLE stop_event;
8258 };
8259
8260 static DWORD WINAPI thread_proc(void *param)
8261 {
8262 MSG msg;
8263 struct wnd_event *wnd_event = param;
8264
8265 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8266 100, 100, 200, 200, 0, 0, 0, NULL);
8267 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8268
8269 SetEvent(wnd_event->start_event);
8270
8271 while (GetMessageA(&msg, 0, 0, 0))
8272 {
8273 TranslateMessage(&msg);
8274 DispatchMessageA(&msg);
8275 }
8276
8277 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8278
8279 return 0;
8280 }
8281
8282 static DWORD CALLBACK create_grand_child_thread( void *param )
8283 {
8284 struct wnd_event *wnd_event = param;
8285 HWND hchild;
8286 MSG msg;
8287
8288 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8289 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8290 ok (hchild != 0, "Failed to create child window\n");
8291 flush_events();
8292 flush_sequence();
8293 SetEvent( wnd_event->start_event );
8294
8295 for (;;)
8296 {
8297 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8298 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
8299 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8300 }
8301 return 0;
8302 }
8303
8304 static DWORD CALLBACK create_child_thread( void *param )
8305 {
8306 struct wnd_event *wnd_event = param;
8307 struct wnd_event child_event;
8308 DWORD ret, tid;
8309 MSG msg;
8310
8311 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8312 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8313 ok (child_event.hwnd != 0, "Failed to create child window\n");
8314 SetFocus( child_event.hwnd );
8315 flush_events();
8316 flush_sequence();
8317 child_event.start_event = wnd_event->start_event;
8318 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8319 for (;;)
8320 {
8321 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8322 if (ret != 1) break;
8323 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8324 }
8325 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8326 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8327 return 0;
8328 }
8329
8330 static const char manifest_dep[] =
8331 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8332 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8333 " <file name=\"testdep.dll\" />"
8334 "</assembly>";
8335
8336 static const char manifest_main[] =
8337 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8338 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8339 "<dependency>"
8340 " <dependentAssembly>"
8341 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8342 " </dependentAssembly>"
8343 "</dependency>"
8344 "</assembly>";
8345
8346 static void create_manifest_file(const char *filename, const char *manifest)
8347 {
8348 WCHAR path[MAX_PATH];
8349 HANDLE file;
8350 DWORD size;
8351
8352 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8353 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8354 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8355 WriteFile(file, manifest, strlen(manifest), &size, NULL);
8356 CloseHandle(file);
8357 }
8358
8359 static HANDLE test_create(const char *file)
8360 {
8361 WCHAR path[MAX_PATH];
8362 ACTCTXW actctx;
8363 HANDLE handle;
8364
8365 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8366 memset(&actctx, 0, sizeof(ACTCTXW));
8367 actctx.cbSize = sizeof(ACTCTXW);
8368 actctx.lpSource = path;
8369
8370 handle = pCreateActCtxW(&actctx);
8371 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8372
8373 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8374 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8375 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8376 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8377 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8378 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8379 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8380 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8381 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8382
8383 return handle;
8384 }
8385
8386 static void test_interthread_messages(void)
8387 {
8388 HANDLE hThread, context, handle, event;
8389 ULONG_PTR cookie;
8390 DWORD tid;
8391 WNDPROC proc;
8392 MSG msg;
8393 char buf[256];
8394 int len, expected_len;
8395 struct wnd_event wnd_event;
8396 BOOL ret;
8397
8398 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8399 if (!wnd_event.start_event)
8400 {
8401 win_skip("skipping interthread message test under win9x\n");
8402 return;
8403 }
8404
8405 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8406 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8407
8408 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8409
8410 CloseHandle(wnd_event.start_event);
8411
8412 SetLastError(0xdeadbeef);
8413 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8414 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8415 "wrong error code %d\n", GetLastError());
8416
8417 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8418 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8419
8420 expected_len = lstrlenA("window caption text");
8421 memset(buf, 0, sizeof(buf));
8422 SetLastError(0xdeadbeef);
8423 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8424 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8425 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8426
8427 msg.hwnd = wnd_event.hwnd;
8428 msg.message = WM_GETTEXT;
8429 msg.wParam = sizeof(buf);
8430 msg.lParam = (LPARAM)buf;
8431 memset(buf, 0, sizeof(buf));
8432 SetLastError(0xdeadbeef);
8433 len = DispatchMessageA(&msg);
8434 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8435 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8436
8437 /* the following test causes an exception in user.exe under win9x */
8438 msg.hwnd = wnd_event.hwnd;
8439 msg.message = WM_TIMER;
8440 msg.wParam = 0;
8441 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8442 SetLastError(0xdeadbeef);
8443 len = DispatchMessageA(&msg);
8444 ok(!len && GetLastError() == 0xdeadbeef,
8445 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8446
8447 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8448 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8449
8450 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8451 CloseHandle(hThread);
8452
8453 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8454
8455 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8456 100, 100, 200, 200, 0, 0, 0, NULL);
8457 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8458 flush_events();
8459 flush_sequence();
8460 log_all_parent_messages++;
8461 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8462 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8463 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
8464 for (;;)
8465 {
8466 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8467 if (ret != 1) break;
8468 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8469 }
8470 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
8471 /* now wait for the thread without processing messages; this shouldn't deadlock */
8472 SetEvent( wnd_event.stop_event );
8473 ret = WaitForSingleObject( hThread, 5000 );
8474 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8475 CloseHandle( hThread );
8476
8477 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8478 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8479 CloseHandle( wnd_event.grand_child );
8480
8481 CloseHandle( wnd_event.start_event );
8482 CloseHandle( wnd_event.stop_event );
8483 flush_events();
8484 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8485 log_all_parent_messages--;
8486 DestroyWindow( wnd_event.hwnd );
8487
8488 /* activation context tests */
8489 if (!pActivateActCtx)
8490 {
8491 win_skip("Activation contexts are not supported, skipping\n");
8492 return;
8493 }
8494
8495 create_manifest_file("testdep1.manifest", manifest_dep);
8496 create_manifest_file("main.manifest", manifest_main);
8497
8498 context = test_create("main.manifest");
8499 DeleteFileA("testdep1.manifest");
8500 DeleteFileA("main.manifest");
8501
8502 handle = (void*)0xdeadbeef;
8503 ret = pGetCurrentActCtx(&handle);
8504 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8505 ok(handle == 0, "active context %p\n", handle);
8506
8507 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8508 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8509 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8510 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8511 CloseHandle(wnd_event.start_event);
8512
8513 /* context is activated after thread creation, so it doesn't inherit it by default */
8514 ret = pActivateActCtx(context, &cookie);
8515 ok(ret, "activation failed: %u\n", GetLastError());
8516
8517 handle = 0;
8518 ret = pGetCurrentActCtx(&handle);
8519 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8520 ok(handle != 0, "active context %p\n", handle);
8521 pReleaseActCtx(handle);
8522
8523 /* destination window will test for active context */
8524 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8525 ok(ret, "thread window returned %d\n", ret);
8526
8527 event = CreateEventW(NULL, 0, 0, NULL);
8528 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8529 ok(ret, "thread window returned %d\n", ret);
8530 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8531 CloseHandle(event);
8532
8533 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8534 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8535
8536 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8537 CloseHandle(hThread);
8538
8539 ret = pDeactivateActCtx(0, cookie);
8540 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8541 pReleaseActCtx(context);
8542 }
8543
8544
8545 static const struct message WmVkN[] = {
8546 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8547 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8548 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8549 { WM_CHAR, wparam|lparam, 'n', 1 },
8550 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8551 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8552 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8553 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8554 { 0 }
8555 };
8556 static const struct message WmShiftVkN[] = {
8557 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8558 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8559 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8560 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8561 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8562 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8563 { WM_CHAR, wparam|lparam, 'N', 1 },
8564 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8565 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8566 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8567 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8568 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8569 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8570 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8571 { 0 }
8572 };
8573 static const struct message WmCtrlVkN[] = {
8574 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8575 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8576 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8577 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8578 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8579 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8580 { WM_CHAR, wparam|lparam, 0x000e, 1 },
8581 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8582 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8583 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8584 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8585 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8586 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8587 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8588 { 0 }
8589 };
8590 static const struct message WmCtrlVkN_2[] = {
8591 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8592 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8593 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8594 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8595 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8596 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8597 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8598 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8599 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8600 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8601 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8602 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8603 { 0 }
8604 };
8605 static const struct message WmAltVkN[] = {
8606 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8607 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8608 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8609 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8610 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8611 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8612 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8613 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8614 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8615 { HCBT_SYSCOMMAND, hook },
8616 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8617 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8618 { 0x00AE, sent|defwinproc|optional }, /* XP */
8619 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8620 { WM_INITMENU, sent|defwinproc },
8621 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8622 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8623 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8624 { WM_CAPTURECHANGED, sent|defwinproc },
8625 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8626 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8627 { WM_EXITMENULOOP, sent|defwinproc },
8628 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8629 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8630 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8631 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8632 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8633 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8634 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8635 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8636 { 0 }
8637 };
8638 static const struct message WmAltVkN_2[] = {
8639 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8640 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8641 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8642 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8643 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8644 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8645 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8646 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8647 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8648 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8649 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8650 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8651 { 0 }
8652 };
8653 static const struct message WmCtrlAltVkN[] = {
8654 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8655 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8656 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8657 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8658 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8659 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8660 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8661 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8662 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8663 { WM_CHAR, optional },
8664 { WM_CHAR, sent|optional },
8665 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8666 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8667 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8668 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8669 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8670 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8671 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8672 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8673 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8674 { 0 }
8675 };
8676 static const struct message WmCtrlShiftVkN[] = {
8677 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8678 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8679 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8680 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8681 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8682 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8683 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8684 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8685 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8686 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8687 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8688 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8689 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8690 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8691 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8692 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8693 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8694 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8695 { 0 }
8696 };
8697 static const struct message WmCtrlAltShiftVkN[] = {
8698 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8699 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8700 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8701 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8702 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8703 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8704 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8705 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8706 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8707 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8708 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8709 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8710 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8711 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8712 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8713 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8714 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8715 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8716 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8717 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8718 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8719 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8720 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8721 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8722 { 0 }
8723 };
8724 static const struct message WmAltPressRelease[] = {
8725 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8726 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8727 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8728 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8729 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8730 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8731 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
8732 { HCBT_SYSCOMMAND, hook },
8733 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8734 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8735 { WM_INITMENU, sent|defwinproc },
8736 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8737 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8738 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8739
8740 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
8741
8742 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8743 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8744 { WM_CAPTURECHANGED, sent|defwinproc },
8745 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8746 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8747 { WM_EXITMENULOOP, sent|defwinproc },
8748 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8749 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8750 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8751 { 0 }
8752 };
8753 static const struct message WmShiftMouseButton[] = {
8754 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8755 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8756 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8757 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
8758 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
8759 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
8760 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
8761 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
8762 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
8763 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8764 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8765 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8766 { 0 }
8767 };
8768 static const struct message WmF1Seq[] = {
8769 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
8770 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
8771 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
8772 { WM_KEYF1, wparam|lparam, 0, 0 },
8773 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
8774 { WM_HELP, sent|defwinproc },
8775 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
8776 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
8777 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
8778 { 0 }
8779 };
8780 static const struct message WmVkAppsSeq[] = {
8781 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
8782 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
8783 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
8784 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
8785 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
8786 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
8787 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
8788 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
8789 { 0 }
8790 };
8791 static const struct message WmVkF10Seq[] = {
8792 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8793 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8794 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8795 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8796 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8797 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8798 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8799 { HCBT_SYSCOMMAND, hook },
8800 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8801 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8802 { WM_INITMENU, sent|defwinproc },
8803 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8804 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8805 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8806
8807 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
8808
8809 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8810 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8811 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8812 { WM_CAPTURECHANGED, sent|defwinproc },
8813 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8814 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8815 { WM_EXITMENULOOP, sent|defwinproc },
8816 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8817 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8818 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8819 { 0 }
8820 };
8821 static const struct message WmShiftF10Seq[] = {
8822 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8823 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8824 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
8825 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8826 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8827 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8828 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
8829 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8830 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8831 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8832 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8833 { HCBT_SYSCOMMAND, hook },
8834 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8835 { WM_INITMENU, sent|defwinproc },
8836 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8837 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
8838 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
8839 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
8840 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
8841 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8842 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
8843 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
8844 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
8845 { 0 }
8846 };
8847
8848 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
8849 {
8850 MSG msg;
8851
8852 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
8853 {
8854 struct recvd_message log_msg;
8855
8856 /* ignore some unwanted messages */
8857 if (msg.message == WM_MOUSEMOVE ||
8858 msg.message == WM_TIMER ||
8859 ignore_message( msg.message ))
8860 continue;
8861
8862 log_msg.hwnd = msg.hwnd;
8863 log_msg.message = msg.message;
8864 log_msg.flags = wparam|lparam;
8865 log_msg.wParam = msg.wParam;
8866 log_msg.lParam = msg.lParam;
8867 log_msg.descr = "accel";
8868 add_message(&log_msg);
8869
8870 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
8871 {
8872 TranslateMessage(&msg);
8873 DispatchMessageA(&msg);
8874 }
8875 }
8876 }
8877
8878 static void test_accelerators(void)
8879 {
8880 RECT rc;
8881 POINT pt;
8882 SHORT state;
8883 HACCEL hAccel;
8884 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8885 100, 100, 200, 200, 0, 0, 0, NULL);
8886 BOOL ret;
8887
8888 assert(hwnd != 0);
8889 UpdateWindow(hwnd);
8890 flush_events();
8891 flush_sequence();
8892
8893 SetFocus(hwnd);
8894 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
8895
8896 state = GetKeyState(VK_SHIFT);
8897 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
8898 state = GetKeyState(VK_CAPITAL);
8899 ok(state == 0, "wrong CapsLock state %04x\n", state);
8900
8901 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
8902 assert(hAccel != 0);
8903
8904 flush_events();
8905 pump_msg_loop(hwnd, 0);
8906 flush_sequence();
8907
8908 trace("testing VK_N press/release\n");
8909 flush_sequence();
8910 keybd_event('N', 0, 0, 0);
8911 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8912 pump_msg_loop(hwnd, hAccel);
8913 if (!sequence_cnt) /* we didn't get any message */
8914 {
8915 skip( "queuing key events not supported\n" );
8916 goto done;
8917 }
8918 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8919
8920 trace("testing Shift+VK_N press/release\n");
8921 flush_sequence();
8922 keybd_event(VK_SHIFT, 0, 0, 0);
8923 keybd_event('N', 0, 0, 0);
8924 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8925 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8926 pump_msg_loop(hwnd, hAccel);
8927 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8928
8929 trace("testing Ctrl+VK_N press/release\n");
8930 flush_sequence();
8931 keybd_event(VK_CONTROL, 0, 0, 0);
8932 keybd_event('N', 0, 0, 0);
8933 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8934 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8935 pump_msg_loop(hwnd, hAccel);
8936 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
8937
8938 trace("testing Alt+VK_N press/release\n");
8939 flush_sequence();
8940 keybd_event(VK_MENU, 0, 0, 0);
8941 keybd_event('N', 0, 0, 0);
8942 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8943 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8944 pump_msg_loop(hwnd, hAccel);
8945 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
8946
8947 trace("testing Ctrl+Alt+VK_N press/release 1\n");
8948 flush_sequence();
8949 keybd_event(VK_CONTROL, 0, 0, 0);
8950 keybd_event(VK_MENU, 0, 0, 0);
8951 keybd_event('N', 0, 0, 0);
8952 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8953 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8954 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8955 pump_msg_loop(hwnd, hAccel);
8956 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
8957
8958 ret = DestroyAcceleratorTable(hAccel);
8959 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
8960
8961 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
8962 assert(hAccel != 0);
8963
8964 trace("testing VK_N press/release\n");
8965 flush_sequence();
8966 keybd_event('N', 0, 0, 0);
8967 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8968 pump_msg_loop(hwnd, hAccel);
8969 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8970
8971 trace("testing Shift+VK_N press/release\n");
8972 flush_sequence();
8973 keybd_event(VK_SHIFT, 0, 0, 0);
8974 keybd_event('N', 0, 0, 0);
8975 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8976 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8977 pump_msg_loop(hwnd, hAccel);
8978 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8979
8980 trace("testing Ctrl+VK_N press/release 2\n");
8981 flush_sequence();
8982 keybd_event(VK_CONTROL, 0, 0, 0);
8983 keybd_event('N', 0, 0, 0);
8984 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8985 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8986 pump_msg_loop(hwnd, hAccel);
8987 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
8988
8989 trace("testing Alt+VK_N press/release 2\n");
8990 flush_sequence();
8991 keybd_event(VK_MENU, 0, 0, 0);
8992 keybd_event('N', 0, 0, 0);
8993 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8994 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8995 pump_msg_loop(hwnd, hAccel);
8996 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
8997
8998 trace("testing Ctrl+Alt+VK_N press/release 2\n");
8999 flush_sequence();
9000 keybd_event(VK_CONTROL, 0, 0, 0);
9001 keybd_event(VK_MENU, 0, 0, 0);
9002 keybd_event('N', 0, 0, 0);
9003 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9004 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9005 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9006 pump_msg_loop(hwnd, hAccel);
9007 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9008
9009 trace("testing Ctrl+Shift+VK_N press/release\n");
9010 flush_sequence();
9011 keybd_event(VK_CONTROL, 0, 0, 0);
9012 keybd_event(VK_SHIFT, 0, 0, 0);
9013 keybd_event('N', 0, 0, 0);
9014 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9015 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9016 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9017 pump_msg_loop(hwnd, hAccel);
9018 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9019
9020 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9021 flush_sequence();
9022 keybd_event(VK_CONTROL, 0, 0, 0);
9023 keybd_event(VK_MENU, 0, 0, 0);
9024 keybd_event(VK_SHIFT, 0, 0, 0);
9025 keybd_event('N', 0, 0, 0);
9026 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9027 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9028 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9029 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9030 pump_msg_loop(hwnd, hAccel);
9031 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9032
9033 ret = DestroyAcceleratorTable(hAccel);
9034 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9035 hAccel = 0;
9036
9037 trace("testing Alt press/release\n");
9038 flush_sequence();
9039 keybd_event(VK_MENU, 0, 0, 0);
9040 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9041 keybd_event(VK_MENU, 0, 0, 0);
9042 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9043 pump_msg_loop(hwnd, 0);
9044 ok_sequence(WmAltPressRelease, "Alt press/release", FALSE);
9045
9046 trace("testing VK_F1 press/release\n");
9047 keybd_event(VK_F1, 0, 0, 0);
9048 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9049 pump_msg_loop(hwnd, 0);
9050 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9051
9052 trace("testing VK_APPS press/release\n");
9053 keybd_event(VK_APPS, 0, 0, 0);
9054 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9055 pump_msg_loop(hwnd, 0);
9056 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9057
9058 trace("testing VK_F10 press/release\n");
9059 keybd_event(VK_F10, 0, 0, 0);
9060 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9061 keybd_event(VK_F10, 0, 0, 0);
9062 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9063 pump_msg_loop(hwnd, 0);
9064 ok_sequence(WmVkF10Seq, "VK_F10 press/release", FALSE);
9065
9066 trace("testing SHIFT+F10 press/release\n");
9067 keybd_event(VK_SHIFT, 0, 0, 0);
9068 keybd_event(VK_F10, 0, 0, 0);
9069 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9070 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9071 keybd_event(VK_ESCAPE, 0, 0, 0);
9072 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9073 pump_msg_loop(hwnd, 0);
9074 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9075
9076 trace("testing Shift+MouseButton press/release\n");
9077 /* first, move mouse pointer inside of the window client area */
9078 GetClientRect(hwnd, &rc);
9079 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9080 rc.left += (rc.right - rc.left)/2;
9081 rc.top += (rc.bottom - rc.top)/2;
9082 SetCursorPos(rc.left, rc.top);
9083 SetActiveWindow(hwnd);
9084
9085 flush_events();
9086 flush_sequence();
9087 GetCursorPos(&pt);
9088 if (pt.x == rc.left && pt.y == rc.top)
9089 {
9090 int i;
9091 keybd_event(VK_SHIFT, 0, 0, 0);
9092 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9093 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9094 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9095 pump_msg_loop(hwnd, 0);
9096 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9097 if (i < sequence_cnt)
9098 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9099 else
9100 skip( "Shift+MouseButton event didn't get to the window\n" );
9101 }
9102
9103 done:
9104 if (hAccel) DestroyAcceleratorTable(hAccel);
9105 DestroyWindow(hwnd);
9106 }
9107
9108 /************* window procedures ********************/
9109
9110 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9111 WPARAM wParam, LPARAM lParam)
9112 {
9113 static LONG defwndproc_counter = 0;
9114 static LONG beginpaint_counter = 0;
9115 LRESULT ret;
9116 struct recvd_message msg;
9117
9118 if (ignore_message( message )) return 0;
9119
9120 switch (message)
9121 {
9122 case WM_ENABLE:
9123 {
9124 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9125 ok((BOOL)wParam == !(style & WS_DISABLED),
9126 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9127 break;
9128 }
9129
9130 case WM_CAPTURECHANGED:
9131 if (test_DestroyWindow_flag)
9132 {
9133 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9134 if (style & WS_CHILD)
9135 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9136 else if (style & WS_POPUP)
9137 lParam = WND_POPUP_ID;
9138 else
9139 lParam = WND_PARENT_ID;
9140 }
9141 break;
9142
9143 case WM_NCDESTROY:
9144 {
9145 HWND capture;
9146
9147 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9148 capture = GetCapture();
9149 if (capture)
9150 {
9151 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9152 trace("current capture %p, releasing...\n", capture);
9153 ReleaseCapture();
9154 }
9155 }
9156 /* fall through */
9157 case WM_DESTROY:
9158 if (pGetAncestor)
9159 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9160 if (test_DestroyWindow_flag)
9161 {
9162 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9163 if (style & WS_CHILD)
9164 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9165 else if (style & WS_POPUP)
9166 lParam = WND_POPUP_ID;
9167 else
9168 lParam = WND_PARENT_ID;
9169 }
9170 break;
9171
9172 /* test_accelerators() depends on this */
9173 case WM_NCHITTEST:
9174 return HTCLIENT;
9175
9176 case WM_USER+10:
9177 {
9178 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9179 HANDLE handle, event = (HANDLE)lParam;
9180 BOOL ret;
9181
9182 handle = (void*)0xdeadbeef;
9183 ret = pGetCurrentActCtx(&handle);
9184 ok(ret, "failed to get current context, %u\n", GetLastError());
9185 ok(handle == 0, "got active context %p\n", handle);
9186
9187 memset(&basicinfo, 0xff, sizeof(basicinfo));
9188 ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9189 &basicinfo, sizeof(basicinfo), NULL);
9190 ok(ret, "got %d, error %d\n", ret, GetLastError());
9191 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9192 ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9193
9194 if (event) SetEvent(event);
9195 return 1;
9196 }
9197
9198 /* ignore */
9199 case WM_MOUSEMOVE:
9200 case WM_MOUSEACTIVATE:
9201 case WM_NCMOUSEMOVE:
9202 case WM_SETCURSOR:
9203 case WM_IME_SELECT:
9204 return 0;
9205 }
9206
9207 msg.hwnd = hwnd;
9208 msg.message = message;
9209 msg.flags = sent|wparam|lparam;
9210 if (defwndproc_counter) msg.flags |= defwinproc;
9211 if (beginpaint_counter) msg.flags |= beginpaint;
9212 msg.wParam = wParam;
9213 msg.lParam = lParam;
9214 msg.descr = "MsgCheckProc";
9215 add_message(&msg);
9216
9217 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9218 {
9219 HWND parent = GetParent(hwnd);
9220 RECT rc;
9221 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9222
9223 GetClientRect(parent, &rc);
9224 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9225 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9226 minmax->ptReserved.x, minmax->ptReserved.y,
9227 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9228 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9229 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9230 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9231
9232 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9233 minmax->ptMaxSize.x, rc.right);
9234 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9235 minmax->ptMaxSize.y, rc.bottom);
9236 }
9237
9238 if (message == WM_PAINT)
9239 {
9240 PAINTSTRUCT ps;
9241 beginpaint_counter++;
9242 BeginPaint( hwnd, &ps );
9243 beginpaint_counter--;
9244 EndPaint( hwnd, &ps );
9245 return 0;
9246 }
9247
9248 if (message == WM_CONTEXTMENU)
9249 {
9250 /* don't create context menu */
9251 return 0;
9252 }
9253
9254 defwndproc_counter++;
9255 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9256 : DefWindowProcA(hwnd, message, wParam, lParam);
9257 defwndproc_counter--;
9258
9259 return ret;
9260 }
9261
9262 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9263 {
9264 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9265 }
9266
9267 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9268 {
9269 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9270 }
9271
9272 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9273 {
9274 static LONG defwndproc_counter = 0;
9275 LRESULT ret;
9276 struct recvd_message msg;
9277
9278 if (ignore_message( message )) return 0;
9279
9280 switch (message)
9281 {
9282 case WM_QUERYENDSESSION:
9283 case WM_ENDSESSION:
9284 lParam &= ~0x01; /* Vista adds a 0x01 flag */
9285 break;
9286 }
9287
9288 msg.hwnd = hwnd;
9289 msg.message = message;
9290 msg.flags = sent|wparam|lparam;
9291 if (defwndproc_counter) msg.flags |= defwinproc;
9292 msg.wParam = wParam;
9293 msg.lParam = lParam;
9294 msg.descr = "popup";
9295 add_message(&msg);
9296
9297 if (message == WM_CREATE)
9298 {
9299 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9300 SetWindowLongA(hwnd, GWL_STYLE, style);
9301 }
9302
9303 defwndproc_counter++;
9304 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9305 defwndproc_counter--;
9306
9307 return ret;
9308 }
9309
9310 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9311 {
9312 static LONG defwndproc_counter = 0;
9313 static LONG beginpaint_counter = 0;
9314 LRESULT ret;
9315 struct recvd_message msg;
9316
9317 if (ignore_message( message )) return 0;
9318
9319 if (log_all_parent_messages ||
9320 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9321 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9322 message == WM_ENABLE || message == WM_ENTERIDLE ||
9323 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9324 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9325 {
9326 switch (message)
9327 {
9328 /* ignore */
9329 case WM_NCHITTEST:
9330 return HTCLIENT;
9331 case WM_SETCURSOR:
9332 case WM_MOUSEMOVE:
9333 case WM_NCMOUSEMOVE:
9334 return 0;
9335
9336 case WM_ERASEBKGND:
9337 {
9338 RECT rc;
9339 INT ret = GetClipBox((HDC)wParam, &rc);
9340
9341 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9342 break;
9343 }
9344 }
9345
9346 msg.hwnd = hwnd;
9347 msg.message = message;
9348 msg.flags = sent|parent|wparam|lparam;
9349 if (defwndproc_counter) msg.flags |= defwinproc;
9350 if (beginpaint_counter) msg.flags |= beginpaint;
9351 msg.wParam = wParam;
9352 msg.lParam = lParam;
9353 msg.descr = "parent";
9354 add_message(&msg);
9355 }
9356
9357 if (message == WM_PAINT)
9358 {
9359 PAINTSTRUCT ps;
9360 beginpaint_counter++;
9361 BeginPaint( hwnd, &ps );
9362 beginpaint_counter--;
9363 EndPaint( hwnd, &ps );
9364 return 0;
9365 }
9366
9367 defwndproc_counter++;
9368 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9369 defwndproc_counter--;
9370
9371 return message == WM_COMPAREITEM ? -1 : ret;
9372 }
9373
9374 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9375 {
9376 if (message == WM_CREATE)
9377 PostMessageA(hwnd, WM_CLOSE, 0, 0);
9378 else if (message == WM_CLOSE)
9379 {
9380 /* Only the first WM_QUIT will survive the window destruction */
9381 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9382 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9383 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9384 }
9385
9386 return DefWindowProcA(hwnd, message, wp, lp);
9387 }
9388
9389 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9390 {
9391 static LONG defwndproc_counter = 0;
9392 LRESULT ret;
9393 struct recvd_message msg;
9394
9395 if (ignore_message( message )) return 0;
9396
9397 if (test_def_id)
9398 {
9399 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9400 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9401 if (after_end_dialog)
9402 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9403 else
9404 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9405 }
9406
9407 msg.hwnd = hwnd;
9408 msg.message = message;
9409 msg.flags = sent|wparam|lparam;
9410 if (defwndproc_counter) msg.flags |= defwinproc;
9411 msg.wParam = wParam;
9412 msg.lParam = lParam;
9413 msg.descr = "dialog";
9414 add_message(&msg);
9415
9416 defwndproc_counter++;
9417 ret = DefDlgProcA(hwnd, message, wParam, lParam);
9418 defwndproc_counter--;
9419
9420 return ret;
9421 }
9422
9423 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9424 {
9425 static LONG defwndproc_counter = 0;
9426 LRESULT ret;
9427 struct recvd_message msg;
9428
9429 /* log only specific messages we are interested in */
9430 switch (message)
9431 {
9432 #if 0 /* probably log these as well */
9433 case WM_ACTIVATE:
9434 case WM_SETFOCUS:
9435 case WM_KILLFOCUS:
9436 #endif
9437 case WM_SHOWWINDOW:
9438 case WM_SIZE:
9439 case WM_MOVE:
9440 case WM_GETMINMAXINFO:
9441 case WM_WINDOWPOSCHANGING:
9442 case WM_WINDOWPOSCHANGED:
9443 break;
9444
9445 default: /* ignore */
9446 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9447 return DefWindowProcA(hwnd, message, wParam, lParam);
9448 }
9449
9450 msg.hwnd = hwnd;
9451 msg.message = message;
9452 msg.flags = sent|wparam|lparam;
9453 if (defwndproc_counter) msg.flags |= defwinproc;
9454 msg.wParam = wParam;
9455 msg.lParam = lParam;
9456 msg.descr = "show";
9457 add_message(&msg);
9458
9459 defwndproc_counter++;
9460 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9461 defwndproc_counter--;
9462
9463 return ret;
9464 }
9465
9466 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
9467 {
9468 switch (msg)
9469 {
9470 case WM_CREATE: return 0;
9471 case WM_PAINT:
9472 {
9473 MSG msg2;
9474 static int i = 0;
9475
9476 if (i < 256)
9477 {
9478 i++;
9479 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9480 {
9481 TranslateMessage(&msg2);
9482 DispatchMessageA(&msg2);
9483 }
9484 i--;
9485 }
9486 else ok(broken(1), "infinite loop\n");
9487 if ( i == 0)
9488 paint_loop_done = TRUE;
9489 return DefWindowProcA(hWnd,msg,wParam,lParam);
9490 }
9491 }
9492 return DefWindowProcA(hWnd,msg,wParam,lParam);
9493 }
9494
9495 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9496 {
9497 static LONG defwndproc_counter = 0;
9498 LRESULT ret;
9499 struct recvd_message msg;
9500 DWORD queue_status;
9501
9502 if (ignore_message( message )) return 0;
9503
9504 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9505 message == WM_HOTKEY || message >= WM_APP)
9506 {
9507 msg.hwnd = hwnd;
9508 msg.message = message;
9509 msg.flags = sent|wparam|lparam;
9510 if (defwndproc_counter) msg.flags |= defwinproc;
9511 msg.wParam = wParam;
9512 msg.lParam = lParam;
9513 msg.descr = "HotkeyMsgCheckProcA";
9514 add_message(&msg);
9515 }
9516
9517 defwndproc_counter++;
9518 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9519 defwndproc_counter--;
9520
9521 if (message == WM_APP)
9522 {
9523 queue_status = GetQueueStatus(QS_HOTKEY);
9524 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9525 queue_status = GetQueueStatus(QS_POSTMESSAGE);
9526 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9527 PostMessageA(hwnd, WM_APP+1, 0, 0);
9528 }
9529 else if (message == WM_APP+1)
9530 {
9531 queue_status = GetQueueStatus(QS_HOTKEY);
9532 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9533 }
9534
9535 return ret;
9536 }
9537
9538 static BOOL RegisterWindowClasses(void)
9539 {
9540 WNDCLASSA cls;
9541 WNDCLASSW clsW;
9542
9543 cls.style = 0;
9544 cls.lpfnWndProc = MsgCheckProcA;
9545 cls.cbClsExtra = 0;
9546 cls.cbWndExtra = 0;
9547 cls.hInstance = GetModuleHandleA(0);
9548 cls.hIcon = 0;
9549 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9550 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9551 cls.lpszMenuName = NULL;
9552 cls.lpszClassName = "TestWindowClass";
9553 if(!RegisterClassA(&cls)) return FALSE;
9554
9555 cls.lpfnWndProc = HotkeyMsgCheckProcA;
9556 cls.lpszClassName = "HotkeyWindowClass";
9557 if(!RegisterClassA(&cls)) return FALSE;
9558
9559 cls.lpfnWndProc = ShowWindowProcA;
9560 cls.lpszClassName = "ShowWindowClass";
9561 if(!RegisterClassA(&cls)) return FALSE;
9562
9563 cls.lpfnWndProc = PopupMsgCheckProcA;
9564 cls.lpszClassName = "TestPopupClass";
9565 if(!RegisterClassA(&cls)) return FALSE;
9566
9567 cls.lpfnWndProc = ParentMsgCheckProcA;
9568 cls.lpszClassName = "TestParentClass";
9569 if(!RegisterClassA(&cls)) return FALSE;
9570
9571 cls.lpfnWndProc = StopQuitMsgCheckProcA;
9572 cls.lpszClassName = "StopQuitClass";
9573 if(!RegisterClassA(&cls)) return FALSE;
9574
9575 cls.lpfnWndProc = DefWindowProcA;
9576 cls.lpszClassName = "SimpleWindowClass";
9577 if(!RegisterClassA(&cls)) return FALSE;
9578
9579 cls.lpfnWndProc = PaintLoopProcA;
9580 cls.lpszClassName = "PaintLoopWindowClass";
9581 if(!RegisterClassA(&cls)) return FALSE;
9582
9583 cls.style = CS_NOCLOSE;
9584 cls.lpszClassName = "NoCloseWindowClass";
9585 if(!RegisterClassA(&cls)) return FALSE;
9586
9587 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9588 cls.style = 0;
9589 cls.hInstance = GetModuleHandleA(0);
9590 cls.hbrBackground = 0;
9591 cls.lpfnWndProc = TestDlgProcA;
9592 cls.lpszClassName = "TestDialogClass";
9593 if(!RegisterClassA(&cls)) return FALSE;
9594
9595 clsW.style = 0;
9596 clsW.lpfnWndProc = MsgCheckProcW;
9597 clsW.cbClsExtra = 0;
9598 clsW.cbWndExtra = 0;
9599 clsW.hInstance = GetModuleHandleW(0);
9600 clsW.hIcon = 0;
9601 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9602 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9603 clsW.lpszMenuName = NULL;
9604 clsW.lpszClassName = testWindowClassW;
9605 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
9606
9607 return TRUE;
9608 }
9609
9610 static BOOL is_our_logged_class(HWND hwnd)
9611 {
9612 char buf[256];
9613
9614 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9615 {
9616 if (!lstrcmpiA(buf, "TestWindowClass") ||
9617 !lstrcmpiA(buf, "ShowWindowClass") ||
9618 !lstrcmpiA(buf, "TestParentClass") ||
9619 !lstrcmpiA(buf, "TestPopupClass") ||
9620 !lstrcmpiA(buf, "SimpleWindowClass") ||
9621 !lstrcmpiA(buf, "TestDialogClass") ||
9622 !lstrcmpiA(buf, "MDI_frame_class") ||
9623 !lstrcmpiA(buf, "MDI_client_class") ||
9624 !lstrcmpiA(buf, "MDI_child_class") ||
9625 !lstrcmpiA(buf, "my_button_class") ||
9626 !lstrcmpiA(buf, "my_edit_class") ||
9627 !lstrcmpiA(buf, "static") ||
9628 !lstrcmpiA(buf, "ListBox") ||
9629 !lstrcmpiA(buf, "ComboBox") ||
9630 !lstrcmpiA(buf, "MyDialogClass") ||
9631 !lstrcmpiA(buf, "#32770") ||
9632 !lstrcmpiA(buf, "#32768"))
9633 return TRUE;
9634 }
9635 return FALSE;
9636 }
9637
9638 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9639 {
9640 HWND hwnd;
9641
9642 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9643
9644 if (nCode == HCBT_CLICKSKIPPED)
9645 {
9646 /* ignore this event, XP sends it a lot when switching focus between windows */
9647 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9648 }
9649
9650 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9651 {
9652 struct recvd_message msg;
9653
9654 msg.hwnd = 0;
9655 msg.message = nCode;
9656 msg.flags = hook|wparam|lparam;
9657 msg.wParam = wParam;
9658 msg.lParam = lParam;
9659 msg.descr = "CBT";
9660 add_message(&msg);
9661
9662 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9663 }
9664
9665 if (nCode == HCBT_DESTROYWND)
9666 {
9667 if (test_DestroyWindow_flag)
9668 {
9669 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9670 if (style & WS_CHILD)
9671 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9672 else if (style & WS_POPUP)
9673 lParam = WND_POPUP_ID;
9674 else
9675 lParam = WND_PARENT_ID;
9676 }
9677 }
9678
9679 /* Log also SetFocus(0) calls */
9680 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9681
9682 if (is_our_logged_class(hwnd))
9683 {
9684 struct recvd_message msg;
9685
9686 msg.hwnd = hwnd;
9687 msg.message = nCode;
9688 msg.flags = hook|wparam|lparam;
9689 msg.wParam = wParam;
9690 msg.lParam = lParam;
9691 msg.descr = "CBT";
9692 add_message(&msg);
9693 }
9694 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9695 }
9696
9697 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
9698 DWORD event,
9699 HWND hwnd,
9700 LONG object_id,
9701 LONG child_id,
9702 DWORD thread_id,
9703 DWORD event_time)
9704 {
9705 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9706
9707 /* ignore mouse cursor events */
9708 if (object_id == OBJID_CURSOR) return;
9709
9710 if (!hwnd || is_our_logged_class(hwnd))
9711 {
9712 struct recvd_message msg;
9713
9714 msg.hwnd = hwnd;
9715 msg.message = event;
9716 msg.flags = winevent_hook|wparam|lparam;
9717 msg.wParam = object_id;
9718 msg.lParam = child_id;
9719 msg.descr = "WEH";
9720 add_message(&msg);
9721 }
9722 }
9723
9724 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
9725 static const WCHAR wszAnsi[] = {'U',0};
9726
9727 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
9728 {
9729 switch (uMsg)
9730 {
9731 case CB_FINDSTRINGEXACT:
9732 trace("String: %p\n", (LPCWSTR)lParam);
9733 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
9734 return 1;
9735 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
9736 return 0;
9737 return -1;
9738 }
9739 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
9740 }
9741
9742 static const struct message WmGetTextLengthAfromW[] = {
9743 { WM_GETTEXTLENGTH, sent },
9744 { WM_GETTEXT, sent|optional },
9745 { 0 }
9746 };
9747
9748 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
9749
9750 /* dummy window proc for WM_GETTEXTLENGTH test */
9751 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
9752 {
9753 switch(msg)
9754 {
9755 case WM_GETTEXTLENGTH:
9756 return lstrlenW(dummy_window_text) + 37; /* some random length */
9757 case WM_GETTEXT:
9758 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
9759 return lstrlenW( (LPWSTR)lp );
9760 default:
9761 return DefWindowProcW( hwnd, msg, wp, lp );
9762 }
9763 }
9764
9765 static void test_message_conversion(void)
9766 {
9767 static const WCHAR wszMsgConversionClass[] =
9768 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
9769 WNDCLASSW cls;
9770 LRESULT lRes;
9771 HWND hwnd;
9772 WNDPROC wndproc, newproc;
9773 BOOL ret;
9774
9775 cls.style = 0;
9776 cls.lpfnWndProc = MsgConversionProcW;
9777 cls.cbClsExtra = 0;
9778 cls.cbWndExtra = 0;
9779 cls.hInstance = GetModuleHandleW(NULL);
9780 cls.hIcon = NULL;
9781 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
9782 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
9783 cls.lpszMenuName = NULL;
9784 cls.lpszClassName = wszMsgConversionClass;
9785 /* this call will fail on Win9x, but that doesn't matter as this test is
9786 * meaningless on those platforms */
9787 if(!RegisterClassW(&cls)) return;
9788
9789 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
9790 100, 100, 200, 200, 0, 0, 0, NULL);
9791 ok(hwnd != NULL, "Window creation failed\n");
9792
9793 /* {W, A} -> A */
9794
9795 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
9796 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9797 ok(lRes == 0, "String should have been converted\n");
9798 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9799 ok(lRes == 1, "String shouldn't have been converted\n");
9800
9801 /* {W, A} -> W */
9802
9803 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
9804 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9805 ok(lRes == 1, "String shouldn't have been converted\n");
9806 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9807 ok(lRes == 1, "String shouldn't have been converted\n");
9808
9809 /* Synchronous messages */
9810
9811 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9812 ok(lRes == 0, "String should have been converted\n");
9813 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9814 ok(lRes == 1, "String shouldn't have been converted\n");
9815
9816 /* Asynchronous messages */
9817
9818 SetLastError(0);
9819 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9820 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9821 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9822 SetLastError(0);
9823 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9824 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9825 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9826 SetLastError(0);
9827 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9828 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9829 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9830 SetLastError(0);
9831 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9832 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9833 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9834 SetLastError(0);
9835 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9836 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9837 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9838 SetLastError(0);
9839 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9840 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9841 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9842 SetLastError(0);
9843 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9844 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9845 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9846 SetLastError(0);
9847 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9848 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9849 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9850
9851 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
9852
9853 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
9854 WS_OVERLAPPEDWINDOW,
9855 100, 100, 200, 200, 0, 0, 0, NULL);
9856 assert(hwnd);
9857 flush_sequence();
9858 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
9859 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9860 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9861 "got bad length %ld\n", lRes );
9862
9863 flush_sequence();
9864 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
9865 hwnd, WM_GETTEXTLENGTH, 0, 0);
9866 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9867 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9868 "got bad length %ld\n", lRes );
9869
9870 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
9871 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
9872 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9873 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9874 NULL, 0, NULL, NULL ) ||
9875 broken(lRes == lstrlenW(dummy_window_text) + 37),
9876 "got bad length %ld\n", lRes );
9877
9878 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
9879 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9880 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9881 NULL, 0, NULL, NULL ) ||
9882 broken(lRes == lstrlenW(dummy_window_text) + 37),
9883 "got bad length %ld\n", lRes );
9884
9885 ret = DestroyWindow(hwnd);
9886 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9887 }
9888
9889 struct timer_info
9890 {
9891 HWND hWnd;
9892 HANDLE handles[2];
9893 DWORD id;
9894 };
9895
9896 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
9897 {
9898 }
9899
9900 #define TIMER_ID 0x19
9901 #define TIMER_COUNT_EXPECTED 100
9902 #define TIMER_COUNT_TOLERANCE 10
9903
9904 static int count = 0;
9905 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9906 {
9907 count++;
9908 }
9909
9910 static DWORD exception;
9911 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9912 {
9913 count++;
9914 RaiseException(exception, 0, 0, NULL);
9915 }
9916
9917 static DWORD WINAPI timer_thread_proc(LPVOID x)
9918 {
9919 struct timer_info *info = x;
9920 DWORD r;
9921
9922 r = KillTimer(info->hWnd, 0x19);
9923 ok(r,"KillTimer failed in thread\n");
9924 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
9925 ok(r,"SetTimer failed in thread\n");
9926 ok(r==TIMER_ID,"SetTimer id different\n");
9927 r = SetEvent(info->handles[0]);
9928 ok(r,"SetEvent failed in thread\n");
9929 return 0;
9930 }
9931
9932 static void test_timers(void)
9933 {
9934 struct timer_info info;
9935 DWORD start;
9936 DWORD id;
9937 MSG msg;
9938
9939 info.hWnd = CreateWindowA("TestWindowClass", NULL,
9940 WS_OVERLAPPEDWINDOW ,
9941 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9942 NULL, NULL, 0);
9943
9944 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
9945 ok(info.id, "SetTimer failed\n");
9946 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
9947 info.handles[0] = CreateEventW(NULL,0,0,NULL);
9948 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
9949
9950 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
9951
9952 WaitForSingleObject(info.handles[1], INFINITE);
9953
9954 CloseHandle(info.handles[0]);
9955 CloseHandle(info.handles[1]);
9956
9957 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
9958
9959 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
9960 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
9961 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
9962 * ±9 counts (~4 ms) around the expected value.
9963 */
9964 count = 0;
9965 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
9966 ok(id != 0, "did not get id from SetTimer.\n");
9967 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9968 start = GetTickCount();
9969 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9970 DispatchMessageA(&msg);
9971 todo_wine
9972 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
9973 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
9974 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
9975 "did not get expected count for minimum timeout (%d != ~%d).\n",
9976 count, TIMER_COUNT_EXPECTED);
9977 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
9978 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
9979 if (pSetSystemTimer)
9980 {
9981 int syscount = 0;
9982
9983 count = 0;
9984 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
9985 ok(id != 0, "did not get id from SetSystemTimer.\n");
9986 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9987 start = GetTickCount();
9988 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9989 {
9990 if (msg.message == WM_SYSTIMER)
9991 syscount++;
9992 DispatchMessageA(&msg);
9993 }
9994 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
9995 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
9996 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
9997 "did not get expected count for minimum timeout (%d != ~%d).\n",
9998 syscount, TIMER_COUNT_EXPECTED);
9999 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
10000 count);
10001 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10002 }
10003
10004 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10005 }
10006
10007 static void test_timers_no_wnd(void)
10008 {
10009 static UINT_PTR ids[0xffff];
10010 UINT_PTR id, id2;
10011 DWORD start;
10012 MSG msg;
10013 int i;
10014
10015 count = 0;
10016 id = SetTimer(NULL, 0, 100, callback_count);
10017 ok(id != 0, "did not get id from SetTimer.\n");
10018 id2 = SetTimer(NULL, id, 200, callback_count);
10019 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10020 Sleep(150);
10021 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10022 ok(count == 0, "did not get zero count as expected (%i).\n", count);
10023 Sleep(150);
10024 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10025 ok(count == 1, "did not get one count as expected (%i).\n", count);
10026 KillTimer(NULL, id);
10027 Sleep(250);
10028 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10029 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10030
10031 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10032 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10033 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10034 * ±9 counts (~4 ms) around the expected value.
10035 */
10036 count = 0;
10037 id = SetTimer(NULL, 0, 0, callback_count);
10038 ok(id != 0, "did not get id from SetTimer.\n");
10039 start = GetTickCount();
10040 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10041 DispatchMessageA(&msg);
10042 todo_wine
10043 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10044 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
10045 "did not get expected count for minimum timeout (%d != ~%d).\n",
10046 count, TIMER_COUNT_EXPECTED);
10047 KillTimer(NULL, id);
10048 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10049
10050 if (pSetCoalescableTimer)
10051 {
10052 count = 0;
10053 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10054 ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10055 start = GetTickCount();
10056 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10057 DispatchMessageA(&msg);
10058 ok(count > 1, "expected count > 1, got %d.\n", count);
10059 KillTimer(NULL, id);
10060 }
10061 else
10062 win_skip("SetCoalescableTimer not available.\n");
10063
10064 /* Check what happens when we're running out of timers */
10065 for (i=0; i<sizeof(ids)/sizeof(ids[0]); i++)
10066 {
10067 SetLastError(0xdeadbeef);
10068 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10069 if (!ids[i]) break;
10070 }
10071 ok(i != sizeof(ids)/sizeof(ids[0]), "all timers were created successfully\n");
10072 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10073 "GetLastError() = %d\n", GetLastError());
10074 while (i > 0) KillTimer(NULL, ids[--i]);
10075 }
10076
10077 static void test_timers_exception(DWORD code)
10078 {
10079 UINT_PTR id;
10080 MSG msg;
10081
10082 exception = code;
10083 id = SetTimer(NULL, 0, 1000, callback_exception);
10084 ok(id != 0, "did not get id from SetTimer.\n");
10085
10086 memset(&msg, 0, sizeof(msg));
10087 msg.message = WM_TIMER;
10088 msg.wParam = id;
10089 msg.lParam = (LPARAM)callback_exception;
10090
10091 count = 0;
10092 DispatchMessageA(&msg);
10093 ok(count == 1, "did not get one count as expected (%i).\n", count);
10094
10095 KillTimer(NULL, id);
10096 }
10097
10098 static void test_timers_exceptions(void)
10099 {
10100 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10101 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10102 test_timers_exception(EXCEPTION_BREAKPOINT);
10103 test_timers_exception(EXCEPTION_SINGLE_STEP);
10104 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10105 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10106 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10107 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10108 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10109 test_timers_exception(0xE000BEEF); /* customer exception */
10110 }
10111
10112 /* Various win events with arbitrary parameters */
10113 static const struct message WmWinEventsSeq[] = {
10114 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10115 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10116 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10117 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10118 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10119 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10120 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10121 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10122 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10123 /* our win event hook ignores OBJID_CURSOR events */
10124 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10125 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10126 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10127 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10128 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10129 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10130 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10131 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10132 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10133 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10134 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10135 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10136 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10137 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10138 { 0 }
10139 };
10140 static const struct message WmWinEventCaretSeq[] = {
10141 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10142 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10143 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10144 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10145 { 0 }
10146 };
10147 static const struct message WmWinEventCaretSeq_2[] = {
10148 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10149 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10150 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10151 { 0 }
10152 };
10153 static const struct message WmWinEventAlertSeq[] = {
10154 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10155 { 0 }
10156 };
10157 static const struct message WmWinEventAlertSeq_2[] = {
10158 /* create window in the thread proc */
10159 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10160 /* our test event */
10161 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10162 { 0 }
10163 };
10164 static const struct message WmGlobalHookSeq_1[] = {
10165 /* create window in the thread proc */
10166 { HCBT_CREATEWND, hook|lparam, 0, 2 },
10167 /* our test events */
10168 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10169 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10170 { 0 }
10171 };
10172 static const struct message WmGlobalHookSeq_2[] = {
10173 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10174 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10175 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10176 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10177 { 0 }
10178 };
10179
10180 static const struct message WmMouseLLHookSeq[] = {
10181 { WM_MOUSEMOVE, hook },
10182 { WM_LBUTTONUP, hook },
10183 { WM_MOUSEMOVE, hook },
10184 { 0 }
10185 };
10186
10187 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10188 DWORD event,
10189 HWND hwnd,
10190 LONG object_id,
10191 LONG child_id,
10192 DWORD thread_id,
10193 DWORD event_time)
10194 {
10195 char buf[256];
10196
10197 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10198 {
10199 if (!lstrcmpiA(buf, "TestWindowClass") ||
10200 !lstrcmpiA(buf, "static"))
10201 {
10202 struct recvd_message msg;
10203
10204 msg.hwnd = hwnd;
10205 msg.message = event;
10206 msg.flags = winevent_hook|wparam|lparam;
10207 msg.wParam = object_id;
10208 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10209 msg.descr = "WEH_2";
10210 add_message(&msg);
10211 }
10212 }
10213 }
10214
10215 static HHOOK hCBT_global_hook;
10216 static DWORD cbt_global_hook_thread_id;
10217
10218 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10219 {
10220 HWND hwnd;
10221 char buf[256];
10222
10223 if (nCode == HCBT_SYSCOMMAND)
10224 {
10225 struct recvd_message msg;
10226
10227 msg.hwnd = 0;
10228 msg.message = nCode;
10229 msg.flags = hook|wparam|lparam;
10230 msg.wParam = wParam;
10231 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10232 msg.descr = "CBT_2";
10233 add_message(&msg);
10234
10235 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10236 }
10237 /* WH_MOUSE_LL hook */
10238 if (nCode == HC_ACTION)
10239 {
10240 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10241
10242 /* we can't test for real mouse events */
10243 if (mhll->flags & LLMHF_INJECTED)
10244 {
10245 struct recvd_message msg;
10246
10247 memset (&msg, 0, sizeof (msg));
10248 msg.message = wParam;
10249 msg.flags = hook;
10250 msg.descr = "CBT_2";
10251 add_message(&msg);
10252 }
10253 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10254 }
10255
10256 /* Log also SetFocus(0) calls */
10257 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10258
10259 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10260 {
10261 if (!lstrcmpiA(buf, "TestWindowClass") ||
10262 !lstrcmpiA(buf, "static"))
10263 {
10264 struct recvd_message msg;
10265
10266 msg.hwnd = hwnd;
10267 msg.message = nCode;
10268 msg.flags = hook|wparam|lparam;
10269 msg.wParam = wParam;
10270 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10271 msg.descr = "CBT_2";
10272 add_message(&msg);
10273 }
10274 }
10275 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10276 }
10277
10278 static DWORD WINAPI win_event_global_thread_proc(void *param)
10279 {
10280 HWND hwnd;
10281 MSG msg;
10282 HANDLE hevent = *(HANDLE *)param;
10283
10284 assert(pNotifyWinEvent);
10285
10286 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10287 assert(hwnd);
10288 trace("created thread window %p\n", hwnd);
10289
10290 *(HWND *)param = hwnd;
10291
10292 flush_sequence();
10293 /* this event should be received only by our new hook proc,
10294 * an old one does not expect an event from another thread.
10295 */
10296 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10297 SetEvent(hevent);
10298
10299 while (GetMessageA(&msg, 0, 0, 0))
10300 {
10301 TranslateMessage(&msg);
10302 DispatchMessageA(&msg);
10303 }
10304 return 0;
10305 }
10306
10307 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10308 {
10309 HWND hwnd;
10310 MSG msg;
10311 HANDLE hevent = *(HANDLE *)param;
10312
10313 flush_sequence();
10314 /* these events should be received only by our new hook proc,
10315 * an old one does not expect an event from another thread.
10316 */
10317
10318 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10319 assert(hwnd);
10320 trace("created thread window %p\n", hwnd);
10321
10322 *(HWND *)param = hwnd;
10323
10324 /* Windows doesn't like when a thread plays games with the focus,
10325 that leads to all kinds of misbehaviours and failures to activate
10326 a window. So, better keep next lines commented out.
10327 SetFocus(0);
10328 SetFocus(hwnd);*/
10329
10330 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10331 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10332
10333 SetEvent(hevent);
10334
10335 while (GetMessageA(&msg, 0, 0, 0))
10336 {
10337 TranslateMessage(&msg);
10338 DispatchMessageA(&msg);
10339 }
10340 return 0;
10341 }
10342
10343 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10344 {
10345 HWND hwnd;
10346 MSG msg;
10347 HANDLE hevent = *(HANDLE *)param;
10348
10349 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10350 assert(hwnd);
10351 trace("created thread window %p\n", hwnd);
10352
10353 *(HWND *)param = hwnd;
10354
10355 flush_sequence();
10356
10357 /* Windows doesn't like when a thread plays games with the focus,
10358 * that leads to all kinds of misbehaviours and failures to activate
10359 * a window. So, better don't generate a mouse click message below.
10360 */
10361 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10362 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10363 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10364
10365 SetEvent(hevent);
10366 while (GetMessageA(&msg, 0, 0, 0))
10367 {
10368 TranslateMessage(&msg);
10369 DispatchMessageA(&msg);
10370 }
10371 return 0;
10372 }
10373
10374 static void test_winevents(void)
10375 {
10376 BOOL ret;
10377 MSG msg;
10378 HWND hwnd, hwnd2;
10379 UINT i;
10380 HANDLE hthread, hevent;
10381 DWORD tid;
10382 HWINEVENTHOOK hhook;
10383 const struct message *events = WmWinEventsSeq;
10384
10385 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10386 WS_OVERLAPPEDWINDOW,
10387 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10388 NULL, NULL, 0);
10389 assert(hwnd);
10390
10391 /****** start of global hook test *************/
10392 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10393 if (!hCBT_global_hook)
10394 {
10395 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10396 skip( "cannot set global hook\n" );
10397 return;
10398 }
10399
10400 hevent = CreateEventA(NULL, 0, 0, NULL);
10401 assert(hevent);
10402 hwnd2 = hevent;
10403
10404 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10405 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10406
10407 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10408
10409 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10410
10411 flush_sequence();
10412 /* this one should be received only by old hook proc */
10413 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10414 /* this one should be received only by old hook proc */
10415 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10416
10417 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10418
10419 ret = UnhookWindowsHookEx(hCBT_global_hook);
10420 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10421
10422 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10423 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10424 CloseHandle(hthread);
10425 CloseHandle(hevent);
10426 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10427 /****** end of global hook test *************/
10428
10429 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10430 {
10431 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10432 return;
10433 }
10434
10435 flush_sequence();
10436
10437 if (0)
10438 {
10439 /* this test doesn't pass under Win9x */
10440 /* win2k ignores events with hwnd == 0 */
10441 SetLastError(0xdeadbeef);
10442 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10443 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10444 GetLastError() == 0xdeadbeef, /* Win9x */
10445 "unexpected error %d\n", GetLastError());
10446 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10447 }
10448
10449 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
10450 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10451
10452 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10453
10454 /****** start of event filtering test *************/
10455 hhook = pSetWinEventHook(
10456 EVENT_OBJECT_SHOW, /* 0x8002 */
10457 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10458 GetModuleHandleA(0), win_event_global_hook_proc,
10459 GetCurrentProcessId(), 0,
10460 WINEVENT_INCONTEXT);
10461 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10462
10463 hevent = CreateEventA(NULL, 0, 0, NULL);
10464 assert(hevent);
10465 hwnd2 = hevent;
10466
10467 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10468 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10469
10470 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10471
10472 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10473
10474 flush_sequence();
10475 /* this one should be received only by old hook proc */
10476 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10477 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10478 /* this one should be received only by old hook proc */
10479 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10480
10481 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10482
10483 ret = pUnhookWinEvent(hhook);
10484 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10485
10486 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10487 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10488 CloseHandle(hthread);
10489 CloseHandle(hevent);
10490 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10491 /****** end of event filtering test *************/
10492
10493 /****** start of out of context event test *************/
10494 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10495 win_event_global_hook_proc, GetCurrentProcessId(), 0,
10496 WINEVENT_OUTOFCONTEXT);
10497 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10498
10499 hevent = CreateEventA(NULL, 0, 0, NULL);
10500 assert(hevent);
10501 hwnd2 = hevent;
10502
10503 flush_sequence();
10504
10505 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10506 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10507
10508 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10509
10510 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10511 /* process pending winevent messages */
10512 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10513 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10514
10515 flush_sequence();
10516 /* this one should be received only by old hook proc */
10517 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10518 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10519 /* this one should be received only by old hook proc */
10520 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10521
10522 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10523 /* process pending winevent messages */
10524 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10525 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10526
10527 ret = pUnhookWinEvent(hhook);
10528 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10529
10530 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10531 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10532 CloseHandle(hthread);
10533 CloseHandle(hevent);
10534 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10535 /****** end of out of context event test *************/
10536
10537 /****** start of MOUSE_LL hook test *************/
10538 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10539 /* WH_MOUSE_LL is not supported on Win9x platforms */
10540 if (!hCBT_global_hook)
10541 {
10542 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10543 goto skip_mouse_ll_hook_test;
10544 }
10545
10546 hevent = CreateEventA(NULL, 0, 0, NULL);
10547 assert(hevent);
10548 hwnd2 = hevent;
10549
10550 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10551 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10552
10553 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10554 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10555
10556 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10557 flush_sequence();
10558
10559 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10560 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10561 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10562
10563 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10564
10565 ret = UnhookWindowsHookEx(hCBT_global_hook);
10566 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10567
10568 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10569 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10570 CloseHandle(hthread);
10571 CloseHandle(hevent);
10572 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10573 /****** end of MOUSE_LL hook test *************/
10574 skip_mouse_ll_hook_test:
10575
10576 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10577 }
10578
10579 static void test_set_hook(void)
10580 {
10581 BOOL ret;
10582 HHOOK hhook;
10583 HWINEVENTHOOK hwinevent_hook;
10584
10585 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10586 ok(hhook != 0, "local hook does not require hModule set to 0\n");
10587 UnhookWindowsHookEx(hhook);
10588
10589 if (0)
10590 {
10591 /* this test doesn't pass under Win9x: BUG! */
10592 SetLastError(0xdeadbeef);
10593 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10594 ok(!hhook, "global hook requires hModule != 0\n");
10595 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10596 }
10597
10598 SetLastError(0xdeadbeef);
10599 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10600 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10601 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10602 GetLastError() == 0xdeadbeef, /* Win9x */
10603 "unexpected error %d\n", GetLastError());
10604
10605 SetLastError(0xdeadbeef);
10606 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10607 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10608 GetLastError() == 0xdeadbeef, /* Win9x */
10609 "unexpected error %d\n", GetLastError());
10610
10611 if (!pSetWinEventHook || !pUnhookWinEvent) return;
10612
10613 /* even process local incontext hooks require hmodule */
10614 SetLastError(0xdeadbeef);
10615 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10616 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10617 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10618 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10619 GetLastError() == 0xdeadbeef, /* Win9x */
10620 "unexpected error %d\n", GetLastError());
10621
10622 /* even thread local incontext hooks require hmodule */
10623 SetLastError(0xdeadbeef);
10624 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10625 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10626 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10627 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10628 GetLastError() == 0xdeadbeef, /* Win9x */
10629 "unexpected error %d\n", GetLastError());
10630
10631 if (0)
10632 {
10633 /* these 3 tests don't pass under Win9x */
10634 SetLastError(0xdeadbeef);
10635 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10636 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10637 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10638 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10639
10640 SetLastError(0xdeadbeef);
10641 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10642 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10643 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10644 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10645
10646 SetLastError(0xdeadbeef);
10647 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10648 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10649 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10650 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10651 }
10652
10653 SetLastError(0xdeadbeef);
10654 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10655 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10656 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10657 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10658 ret = pUnhookWinEvent(hwinevent_hook);
10659 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10660
10661 todo_wine {
10662 /* This call succeeds under win2k SP4, but fails under Wine.
10663 Does win2k test/use passed process id? */
10664 SetLastError(0xdeadbeef);
10665 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10666 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10667 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10668 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10669 ret = pUnhookWinEvent(hwinevent_hook);
10670 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10671 }
10672
10673 SetLastError(0xdeadbeef);
10674 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10675 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10676 GetLastError() == 0xdeadbeef, /* Win9x */
10677 "unexpected error %d\n", GetLastError());
10678 }
10679
10680 static HWND hook_hwnd;
10681 static HHOOK recursive_hook;
10682 static int hook_depth, max_hook_depth;
10683
10684 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
10685 {
10686 LRESULT res;
10687 MSG msg;
10688 BOOL b;
10689
10690 hook_depth++;
10691 if(hook_depth > max_hook_depth)
10692 max_hook_depth = hook_depth;
10693
10694 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
10695 ok(b, "PeekMessage failed\n");
10696
10697 res = CallNextHookEx(recursive_hook, code, w, l);
10698
10699 hook_depth--;
10700 return res;
10701 }
10702
10703 static void test_recursive_hook(void)
10704 {
10705 MSG msg;
10706 BOOL b;
10707
10708 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
10709 ok(hook_hwnd != NULL, "CreateWindow failed\n");
10710
10711 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
10712 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
10713
10714 PostMessageW(hook_hwnd, WM_USER, 0, 0);
10715 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
10716
10717 hook_depth = 0;
10718 GetMessageW(&msg, hook_hwnd, 0, 0);
10719 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
10720 trace("max_hook_depth = %d\n", max_hook_depth);
10721
10722 b = UnhookWindowsHookEx(recursive_hook);
10723 ok(b, "UnhokWindowsHookEx failed\n");
10724
10725 DestroyWindow(hook_hwnd);
10726 }
10727
10728 static const struct message ScrollWindowPaint1[] = {
10729 { WM_PAINT, sent },
10730 { WM_ERASEBKGND, sent|beginpaint },
10731 { WM_GETTEXTLENGTH, sent|optional },
10732 { WM_PAINT, sent|optional },
10733 { WM_NCPAINT, sent|beginpaint|optional },
10734 { WM_GETTEXT, sent|beginpaint|optional },
10735 { WM_GETTEXT, sent|beginpaint|optional },
10736 { WM_GETTEXT, sent|beginpaint|optional },
10737 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
10738 { WM_ERASEBKGND, sent|beginpaint|optional },
10739 { 0 }
10740 };
10741
10742 static const struct message ScrollWindowPaint2[] = {
10743 { WM_PAINT, sent },
10744 { 0 }
10745 };
10746
10747 static void test_scrollwindowex(void)
10748 {
10749 HWND hwnd, hchild;
10750 RECT rect={0,0,130,130};
10751
10752 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
10753 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
10754 100, 100, 200, 200, 0, 0, 0, NULL);
10755 ok (hwnd != 0, "Failed to create overlapped window\n");
10756 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
10757 WS_VISIBLE|WS_CAPTION|WS_CHILD,
10758 10, 10, 150, 150, hwnd, 0, 0, NULL);
10759 ok (hchild != 0, "Failed to create child\n");
10760 UpdateWindow(hwnd);
10761 flush_events();
10762 flush_sequence();
10763
10764 /* scroll without the child window */
10765 trace("start scroll\n");
10766 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10767 SW_ERASE|SW_INVALIDATE);
10768 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10769 trace("end scroll\n");
10770 flush_sequence();
10771 flush_events();
10772 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10773 flush_events();
10774 flush_sequence();
10775
10776 /* Now without the SW_ERASE flag */
10777 trace("start scroll\n");
10778 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
10779 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10780 trace("end scroll\n");
10781 flush_sequence();
10782 flush_events();
10783 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
10784 flush_events();
10785 flush_sequence();
10786
10787 /* now scroll the child window as well */
10788 trace("start scroll\n");
10789 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10790 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
10791 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
10792 /* windows sometimes a WM_MOVE */
10793 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
10794 trace("end scroll\n");
10795 flush_sequence();
10796 flush_events();
10797 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10798 flush_events();
10799 flush_sequence();
10800
10801 /* now scroll with ScrollWindow() */
10802 trace("start scroll with ScrollWindow\n");
10803 ScrollWindow( hwnd, 5, 5, NULL, NULL);
10804 trace("end scroll\n");
10805 flush_sequence();
10806 flush_events();
10807 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
10808
10809 ok(DestroyWindow(hchild), "failed to destroy window\n");
10810 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10811 flush_sequence();
10812 }
10813
10814 static const struct message destroy_window_with_children[] = {
10815 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10816 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
10817 { 0x0090, sent|optional },
10818 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
10819 { 0x0090, sent|optional },
10820 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10821 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10822 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10823 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10824 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
10825 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10826 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10827 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10828 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10829 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10830 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10831 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10832 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10833 { 0 }
10834 };
10835
10836 static void test_DestroyWindow(void)
10837 {
10838 BOOL ret;
10839 HWND parent, child1, child2, child3, child4, test;
10840 UINT_PTR child_id = WND_CHILD_ID + 1;
10841
10842 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10843 100, 100, 200, 200, 0, 0, 0, NULL);
10844 assert(parent != 0);
10845 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10846 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
10847 assert(child1 != 0);
10848 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10849 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
10850 assert(child2 != 0);
10851 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10852 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
10853 assert(child3 != 0);
10854 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
10855 0, 0, 50, 50, parent, 0, 0, NULL);
10856 assert(child4 != 0);
10857
10858 /* test owner/parent of child2 */
10859 test = GetParent(child2);
10860 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10861 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10862 if(pGetAncestor) {
10863 test = pGetAncestor(child2, GA_PARENT);
10864 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10865 }
10866 test = GetWindow(child2, GW_OWNER);
10867 ok(!test, "wrong owner %p\n", test);
10868
10869 test = SetParent(child2, parent);
10870 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
10871
10872 /* test owner/parent of the parent */
10873 test = GetParent(parent);
10874 ok(!test, "wrong parent %p\n", test);
10875 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
10876 if(pGetAncestor) {
10877 test = pGetAncestor(parent, GA_PARENT);
10878 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10879 }
10880 test = GetWindow(parent, GW_OWNER);
10881 ok(!test, "wrong owner %p\n", test);
10882
10883 /* test owner/parent of child1 */
10884 test = GetParent(child1);
10885 ok(test == parent, "wrong parent %p\n", test);
10886 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
10887 if(pGetAncestor) {
10888 test = pGetAncestor(child1, GA_PARENT);
10889 ok(test == parent, "wrong parent %p\n", test);
10890 }
10891 test = GetWindow(child1, GW_OWNER);
10892 ok(!test, "wrong owner %p\n", test);
10893
10894 /* test owner/parent of child2 */
10895 test = GetParent(child2);
10896 ok(test == parent, "wrong parent %p\n", test);
10897 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10898 if(pGetAncestor) {
10899 test = pGetAncestor(child2, GA_PARENT);
10900 ok(test == parent, "wrong parent %p\n", test);
10901 }
10902 test = GetWindow(child2, GW_OWNER);
10903 ok(!test, "wrong owner %p\n", test);
10904
10905 /* test owner/parent of child3 */
10906 test = GetParent(child3);
10907 ok(test == child1, "wrong parent %p\n", test);
10908 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
10909 if(pGetAncestor) {
10910 test = pGetAncestor(child3, GA_PARENT);
10911 ok(test == child1, "wrong parent %p\n", test);
10912 }
10913 test = GetWindow(child3, GW_OWNER);
10914 ok(!test, "wrong owner %p\n", test);
10915
10916 /* test owner/parent of child4 */
10917 test = GetParent(child4);
10918 ok(test == parent, "wrong parent %p\n", test);
10919 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
10920 if(pGetAncestor) {
10921 test = pGetAncestor(child4, GA_PARENT);
10922 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10923 }
10924 test = GetWindow(child4, GW_OWNER);
10925 ok(test == parent, "wrong owner %p\n", test);
10926
10927 flush_sequence();
10928
10929 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
10930 parent, child1, child2, child3, child4);
10931
10932 SetCapture(child4);
10933 test = GetCapture();
10934 ok(test == child4, "wrong capture window %p\n", test);
10935
10936 test_DestroyWindow_flag = TRUE;
10937 ret = DestroyWindow(parent);
10938 ok( ret, "DestroyWindow() error %d\n", GetLastError());
10939 test_DestroyWindow_flag = FALSE;
10940 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
10941
10942 ok(!IsWindow(parent), "parent still exists\n");
10943 ok(!IsWindow(child1), "child1 still exists\n");
10944 ok(!IsWindow(child2), "child2 still exists\n");
10945 ok(!IsWindow(child3), "child3 still exists\n");
10946 ok(!IsWindow(child4), "child4 still exists\n");
10947
10948 test = GetCapture();
10949 ok(!test, "wrong capture window %p\n", test);
10950 }
10951
10952
10953 static const struct message WmDispatchPaint[] = {
10954 { WM_NCPAINT, sent },
10955 { WM_GETTEXT, sent|defwinproc|optional },
10956 { WM_GETTEXT, sent|defwinproc|optional },
10957 { WM_ERASEBKGND, sent },
10958 { 0 }
10959 };
10960
10961 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10962 {
10963 if (message == WM_PAINT) return 0;
10964 return MsgCheckProcA( hwnd, message, wParam, lParam );
10965 }
10966
10967 static void test_DispatchMessage(void)
10968 {
10969 RECT rect;
10970 MSG msg;
10971 int count;
10972 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10973 100, 100, 200, 200, 0, 0, 0, NULL);
10974 ShowWindow( hwnd, SW_SHOW );
10975 UpdateWindow( hwnd );
10976 flush_events();
10977 flush_sequence();
10978 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
10979
10980 SetRect( &rect, -5, -5, 5, 5 );
10981 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10982 count = 0;
10983 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10984 {
10985 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10986 else
10987 {
10988 flush_sequence();
10989 DispatchMessageA( &msg );
10990 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
10991 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10992 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
10993 if (++count > 10) break;
10994 }
10995 }
10996 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
10997
10998 trace("now without DispatchMessage\n");
10999 flush_sequence();
11000 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11001 count = 0;
11002 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11003 {
11004 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11005 else
11006 {
11007 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11008 flush_sequence();
11009 /* this will send WM_NCCPAINT just like DispatchMessage does */
11010 GetUpdateRgn( hwnd, hrgn, TRUE );
11011 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11012 DeleteObject( hrgn );
11013 GetClientRect( hwnd, &rect );
11014 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
11015 ok( !count, "Got multiple WM_PAINTs\n" );
11016 if (++count > 10) break;
11017 }
11018 }
11019
11020 flush_sequence();
11021 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11022 count = 0;
11023 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11024 {
11025 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11026 else
11027 {
11028 HDC hdc;
11029
11030 flush_sequence();
11031 hdc = BeginPaint( hwnd, NULL );
11032 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11033 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11034 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11035 ok( !count, "Got multiple WM_PAINTs\n" );
11036 if (++count > 10) break;
11037 }
11038 }
11039 DestroyWindow(hwnd);
11040 }
11041
11042
11043 static const struct message WmUser[] = {
11044 { WM_USER, sent },
11045 { 0 }
11046 };
11047
11048 struct sendmsg_info
11049 {
11050 HWND hwnd;
11051 DWORD timeout;
11052 DWORD ret;
11053 };
11054
11055 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11056 {
11057 struct sendmsg_info *info = arg;
11058 SetLastError( 0xdeadbeef );
11059 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11060 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11061 broken(GetLastError() == 0), /* win9x */
11062 "unexpected error %d\n", GetLastError());
11063 return 0;
11064 }
11065
11066 static void wait_for_thread( HANDLE thread )
11067 {
11068 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11069 {
11070 MSG msg;
11071 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11072 }
11073 }
11074
11075 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11076 {
11077 if (message == WM_USER) Sleep(200);
11078 return MsgCheckProcA( hwnd, message, wParam, lParam );
11079 }
11080
11081 static void test_SendMessageTimeout(void)
11082 {
11083 HANDLE thread;
11084 struct sendmsg_info info;
11085 DWORD tid;
11086 BOOL is_win9x;
11087
11088 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11089 100, 100, 200, 200, 0, 0, 0, NULL);
11090 flush_events();
11091 flush_sequence();
11092
11093 info.timeout = 1000;
11094 info.ret = 0xdeadbeef;
11095 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11096 wait_for_thread( thread );
11097 CloseHandle( thread );
11098 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11099 ok_sequence( WmUser, "WmUser", FALSE );
11100
11101 info.timeout = 1;
11102 info.ret = 0xdeadbeef;
11103 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11104 Sleep(100); /* SendMessageTimeout should time out here */
11105 wait_for_thread( thread );
11106 CloseHandle( thread );
11107 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11108 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11109
11110 /* 0 means infinite timeout (but not on win9x) */
11111 info.timeout = 0;
11112 info.ret = 0xdeadbeef;
11113 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11114 Sleep(100);
11115 wait_for_thread( thread );
11116 CloseHandle( thread );
11117 is_win9x = !info.ret;
11118 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11119 else ok_sequence( WmUser, "WmUser", FALSE );
11120
11121 /* timeout is treated as signed despite the prototype (but not on win9x) */
11122 info.timeout = 0x7fffffff;
11123 info.ret = 0xdeadbeef;
11124 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11125 Sleep(100);
11126 wait_for_thread( thread );
11127 CloseHandle( thread );
11128 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11129 ok_sequence( WmUser, "WmUser", FALSE );
11130
11131 info.timeout = 0x80000000;
11132 info.ret = 0xdeadbeef;
11133 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11134 Sleep(100);
11135 wait_for_thread( thread );
11136 CloseHandle( thread );
11137 if (is_win9x)
11138 {
11139 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11140 ok_sequence( WmUser, "WmUser", FALSE );
11141 }
11142 else
11143 {
11144 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11145 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11146 }
11147
11148 /* now check for timeout during message processing */
11149 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11150 info.timeout = 100;
11151 info.ret = 0xdeadbeef;
11152 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11153 wait_for_thread( thread );
11154 CloseHandle( thread );
11155 /* we should time out but still get the message */
11156 ok( info.ret == 0, "SendMessageTimeout failed\n" );
11157 ok_sequence( WmUser, "WmUser", FALSE );
11158
11159 DestroyWindow( info.hwnd );
11160 }
11161
11162
11163 /****************** edit message test *************************/
11164 #define ID_EDIT 0x1234
11165 static const struct message sl_edit_setfocus[] =
11166 {
11167 { HCBT_SETFOCUS, hook },
11168 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11169 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11170 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11171 { WM_SETFOCUS, sent|wparam, 0 },
11172 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11173 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11174 { WM_CTLCOLOREDIT, sent|parent },
11175 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11176 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11177 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11178 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11179 { 0 }
11180 };
11181 static const struct message sl_edit_invisible[] =
11182 {
11183 { HCBT_SETFOCUS, hook },
11184 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11185 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11186 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11187 { WM_KILLFOCUS, sent|parent },
11188 { WM_SETFOCUS, sent },
11189 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11190 { 0 }
11191 };
11192 static const struct message ml_edit_setfocus[] =
11193 {
11194 { HCBT_SETFOCUS, hook },
11195 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11196 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11197 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11198 { WM_SETFOCUS, sent|wparam, 0 },
11199 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11200 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11201 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11202 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11203 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11204 { 0 }
11205 };
11206 static const struct message sl_edit_killfocus[] =
11207 {
11208 { HCBT_SETFOCUS, hook },
11209 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11210 { WM_KILLFOCUS, sent|wparam, 0 },
11211 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11212 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11213 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11214 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11215 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11216 { 0 }
11217 };
11218 static const struct message sl_edit_lbutton_dblclk[] =
11219 {
11220 { WM_LBUTTONDBLCLK, sent },
11221 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11222 { 0 }
11223 };
11224 static const struct message sl_edit_lbutton_down[] =
11225 {
11226 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11227 { HCBT_SETFOCUS, hook },
11228 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11229 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11230 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11231 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11232 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11233 { WM_CTLCOLOREDIT, sent|parent },
11234 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11235 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11236 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11237 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11238 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11239 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11240 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11241 { WM_CTLCOLOREDIT, sent|parent|optional },
11242 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11243 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11244 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11245 { 0 }
11246 };
11247 static const struct message ml_edit_lbutton_down[] =
11248 {
11249 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11250 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11251 { HCBT_SETFOCUS, hook },
11252 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11253 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11254 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11255 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11256 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11257 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11258 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11259 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11260 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11261 { 0 }
11262 };
11263 static const struct message sl_edit_lbutton_up[] =
11264 {
11265 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11266 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11267 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11268 { WM_CAPTURECHANGED, sent|defwinproc },
11269 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11270 { 0 }
11271 };
11272 static const struct message ml_edit_lbutton_up[] =
11273 {
11274 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11275 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11276 { WM_CAPTURECHANGED, sent|defwinproc },
11277 { 0 }
11278 };
11279
11280 static WNDPROC old_edit_proc;
11281
11282 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11283 {
11284 static LONG defwndproc_counter = 0;
11285 LRESULT ret;
11286 struct recvd_message msg;
11287
11288 if (ignore_message( message )) return 0;
11289
11290 msg.hwnd = hwnd;
11291 msg.message = message;
11292 msg.flags = sent|wparam|lparam;
11293 if (defwndproc_counter) msg.flags |= defwinproc;
11294 msg.wParam = wParam;
11295 msg.lParam = lParam;
11296 msg.descr = "edit";
11297 add_message(&msg);
11298
11299 defwndproc_counter++;
11300 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11301 defwndproc_counter--;
11302
11303 return ret;
11304 }
11305
11306 static void subclass_edit(void)
11307 {
11308 WNDCLASSA cls;
11309
11310 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11311
11312 old_edit_proc = cls.lpfnWndProc;
11313
11314 cls.hInstance = GetModuleHandleA(NULL);
11315 cls.lpfnWndProc = edit_hook_proc;
11316 cls.lpszClassName = "my_edit_class";
11317 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11318 if (!RegisterClassA(&cls)) assert(0);
11319 }
11320
11321 static void test_edit_messages(void)
11322 {
11323 HWND hwnd, parent;
11324 DWORD dlg_code;
11325
11326 subclass_edit();
11327 log_all_parent_messages++;
11328
11329 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11330 100, 100, 200, 200, 0, 0, 0, NULL);
11331 ok (parent != 0, "Failed to create parent window\n");
11332
11333 /* test single line edit */
11334 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11335 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11336 ok(hwnd != 0, "Failed to create edit window\n");
11337
11338 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11339 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11340
11341 flush_sequence();
11342 SetFocus(hwnd);
11343 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11344
11345 ShowWindow(hwnd, SW_SHOW);
11346 UpdateWindow(hwnd);
11347 SetFocus(0);
11348 flush_sequence();
11349
11350 SetFocus(hwnd);
11351 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11352
11353 SetFocus(0);
11354 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11355
11356 SetFocus(0);
11357 ReleaseCapture();
11358 flush_sequence();
11359
11360 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11361 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11362
11363 SetFocus(0);
11364 ReleaseCapture();
11365 flush_sequence();
11366
11367 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11368 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11369
11370 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11371 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11372
11373 DestroyWindow(hwnd);
11374
11375 /* test multiline edit */
11376 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11377 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11378 ok(hwnd != 0, "Failed to create edit window\n");
11379
11380 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11381 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11382 "wrong dlg_code %08x\n", dlg_code);
11383
11384 ShowWindow(hwnd, SW_SHOW);
11385 UpdateWindow(hwnd);
11386 SetFocus(0);
11387 flush_sequence();
11388
11389 SetFocus(hwnd);
11390 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11391
11392 SetFocus(0);
11393 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11394
11395 SetFocus(0);
11396 ReleaseCapture();
11397 flush_sequence();
11398
11399 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11400 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11401
11402 SetFocus(0);
11403 ReleaseCapture();
11404 flush_sequence();
11405
11406 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11407 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11408
11409 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11410 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11411
11412 DestroyWindow(hwnd);
11413 DestroyWindow(parent);
11414
11415 log_all_parent_messages--;
11416 }
11417
11418 /**************************** End of Edit test ******************************/
11419
11420 static const struct message WmKeyDownSkippedSeq[] =
11421 {
11422 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11423 { 0 }
11424 };
11425 static const struct message WmKeyDownWasDownSkippedSeq[] =
11426 {
11427 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11428 { 0 }
11429 };
11430 static const struct message WmKeyUpSkippedSeq[] =
11431 {
11432 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11433 { 0 }
11434 };
11435 static const struct message WmUserKeyUpSkippedSeq[] =
11436 {
11437 { WM_USER, sent },
11438 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11439 { 0 }
11440 };
11441
11442 #define EV_STOP 0
11443 #define EV_SENDMSG 1
11444 #define EV_ACK 2
11445
11446 struct peekmsg_info
11447 {
11448 HWND hwnd;
11449 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11450 };
11451
11452 static DWORD CALLBACK send_msg_thread_2(void *param)
11453 {
11454 DWORD ret;
11455 struct peekmsg_info *info = param;
11456
11457 trace("thread: looping\n");
11458 SetEvent(info->hevent[EV_ACK]);
11459
11460 while (1)
11461 {
11462 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
11463
11464 switch (ret)
11465 {
11466 case WAIT_OBJECT_0 + EV_STOP:
11467 trace("thread: exiting\n");
11468 return 0;
11469
11470 case WAIT_OBJECT_0 + EV_SENDMSG:
11471 trace("thread: sending message\n");
11472 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11473 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11474 SetEvent(info->hevent[EV_ACK]);
11475 break;
11476
11477 default:
11478 trace("unexpected return: %04x\n", ret);
11479 assert(0);
11480 break;
11481 }
11482 }
11483 return 0;
11484 }
11485
11486 static void test_PeekMessage(void)
11487 {
11488 MSG msg;
11489 HANDLE hthread;
11490 DWORD tid, qstatus;
11491 UINT qs_all_input = QS_ALLINPUT;
11492 UINT qs_input = QS_INPUT;
11493 BOOL ret;
11494 struct peekmsg_info info;
11495
11496 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11497 100, 100, 200, 200, 0, 0, 0, NULL);
11498 assert(info.hwnd);
11499 ShowWindow(info.hwnd, SW_SHOW);
11500 UpdateWindow(info.hwnd);
11501 SetFocus(info.hwnd);
11502
11503 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11504 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11505 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11506
11507 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11508 WaitForSingleObject(info.hevent[EV_ACK], 10000);
11509
11510 flush_events();
11511 flush_sequence();
11512
11513 SetLastError(0xdeadbeef);
11514 qstatus = GetQueueStatus(qs_all_input);
11515 if (GetLastError() == ERROR_INVALID_FLAGS)
11516 {
11517 trace("QS_RAWINPUT not supported on this platform\n");
11518 qs_all_input &= ~QS_RAWINPUT;
11519 qs_input &= ~QS_RAWINPUT;
11520 }
11521 if (qstatus & QS_POSTMESSAGE)
11522 {
11523 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11524 qstatus = GetQueueStatus(qs_all_input);
11525 }
11526 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11527
11528 trace("signalling to send message\n");
11529 SetEvent(info.hevent[EV_SENDMSG]);
11530 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11531
11532 /* pass invalid QS_xxxx flags */
11533 SetLastError(0xdeadbeef);
11534 qstatus = GetQueueStatus(0xffffffff);
11535 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11536 if (!qstatus)
11537 {
11538 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11539 qstatus = GetQueueStatus(qs_all_input);
11540 }
11541 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
11542 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11543 "wrong qstatus %08x\n", qstatus);
11544
11545 msg.message = 0;
11546 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11547 ok(!ret,
11548 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11549 msg.message);
11550 ok_sequence(WmUser, "WmUser", FALSE);
11551
11552 qstatus = GetQueueStatus(qs_all_input);
11553 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11554
11555 keybd_event('N', 0, 0, 0);
11556 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11557 qstatus = GetQueueStatus(qs_all_input);
11558 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11559 {
11560 skip( "queuing key events not supported\n" );
11561 goto done;
11562 }
11563 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11564 /* keybd_event seems to trigger a sent message on NT4 */
11565 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11566 "wrong qstatus %08x\n", qstatus);
11567
11568 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11569 qstatus = GetQueueStatus(qs_all_input);
11570 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11571 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11572 "wrong qstatus %08x\n", qstatus);
11573
11574 InvalidateRect(info.hwnd, NULL, FALSE);
11575 qstatus = GetQueueStatus(qs_all_input);
11576 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11577 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11578 "wrong qstatus %08x\n", qstatus);
11579
11580 trace("signalling to send message\n");
11581 SetEvent(info.hevent[EV_SENDMSG]);
11582 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11583
11584 qstatus = GetQueueStatus(qs_all_input);
11585 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11586 "wrong qstatus %08x\n", qstatus);
11587
11588 msg.message = 0;
11589 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11590 if (ret && msg.message == WM_CHAR)
11591 {
11592 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11593 goto done;
11594 }
11595 ok(!ret,
11596 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11597 msg.message);
11598 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
11599 {
11600 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11601 goto done;
11602 }
11603 ok_sequence(WmUser, "WmUser", FALSE);
11604
11605 qstatus = GetQueueStatus(qs_all_input);
11606 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11607 "wrong qstatus %08x\n", qstatus);
11608
11609 trace("signalling to send message\n");
11610 SetEvent(info.hevent[EV_SENDMSG]);
11611 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11612
11613 qstatus = GetQueueStatus(qs_all_input);
11614 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11615 "wrong qstatus %08x\n", qstatus);
11616
11617 msg.message = 0;
11618 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11619 ok(!ret,
11620 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11621 msg.message);
11622 ok_sequence(WmUser, "WmUser", FALSE);
11623
11624 qstatus = GetQueueStatus(qs_all_input);
11625 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11626 "wrong qstatus %08x\n", qstatus);
11627
11628 msg.message = 0;
11629 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11630 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11631 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11632 ret, msg.message, msg.wParam);
11633 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11634
11635 qstatus = GetQueueStatus(qs_all_input);
11636 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11637 "wrong qstatus %08x\n", qstatus);
11638
11639 msg.message = 0;
11640 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11641 ok(!ret,
11642 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11643 msg.message);
11644 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11645
11646 qstatus = GetQueueStatus(qs_all_input);
11647 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11648 "wrong qstatus %08x\n", qstatus);
11649
11650 msg.message = 0;
11651 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11652 ok(ret && msg.message == WM_PAINT,
11653 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11654 DispatchMessageA(&msg);
11655 ok_sequence(WmPaint, "WmPaint", FALSE);
11656
11657 qstatus = GetQueueStatus(qs_all_input);
11658 ok(qstatus == MAKELONG(0, QS_KEY),
11659 "wrong qstatus %08x\n", qstatus);
11660
11661 msg.message = 0;
11662 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11663 ok(!ret,
11664 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11665 msg.message);
11666 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11667
11668 qstatus = GetQueueStatus(qs_all_input);
11669 ok(qstatus == MAKELONG(0, QS_KEY),
11670 "wrong qstatus %08x\n", qstatus);
11671
11672 trace("signalling to send message\n");
11673 SetEvent(info.hevent[EV_SENDMSG]);
11674 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11675
11676 qstatus = GetQueueStatus(qs_all_input);
11677 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11678 "wrong qstatus %08x\n", qstatus);
11679
11680 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11681
11682 qstatus = GetQueueStatus(qs_all_input);
11683 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11684 "wrong qstatus %08x\n", qstatus);
11685
11686 msg.message = 0;
11687 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11688 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11689 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11690 ret, msg.message, msg.wParam);
11691 ok_sequence(WmUser, "WmUser", FALSE);
11692
11693 qstatus = GetQueueStatus(qs_all_input);
11694 ok(qstatus == MAKELONG(0, QS_KEY),
11695 "wrong qstatus %08x\n", qstatus);
11696
11697 msg.message = 0;
11698 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11699 ok(!ret,
11700 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11701 msg.message);
11702 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11703
11704 qstatus = GetQueueStatus(qs_all_input);
11705 ok(qstatus == MAKELONG(0, QS_KEY),
11706 "wrong qstatus %08x\n", qstatus);
11707
11708 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11709
11710 qstatus = GetQueueStatus(qs_all_input);
11711 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
11712 "wrong qstatus %08x\n", qstatus);
11713
11714 trace("signalling to send message\n");
11715 SetEvent(info.hevent[EV_SENDMSG]);
11716 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11717
11718 qstatus = GetQueueStatus(qs_all_input);
11719 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11720 "wrong qstatus %08x\n", qstatus);
11721
11722 msg.message = 0;
11723 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
11724 ok(!ret,
11725 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11726 msg.message);
11727 ok_sequence(WmUser, "WmUser", FALSE);
11728
11729 qstatus = GetQueueStatus(qs_all_input);
11730 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11731 "wrong qstatus %08x\n", qstatus);
11732
11733 msg.message = 0;
11734 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11735 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11736 else /* workaround for a missing QS_RAWINPUT support */
11737 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
11738 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11739 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11740 ret, msg.message, msg.wParam);
11741 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11742
11743 qstatus = GetQueueStatus(qs_all_input);
11744 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11745 "wrong qstatus %08x\n", qstatus);
11746
11747 msg.message = 0;
11748 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11749 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11750 else /* workaround for a missing QS_RAWINPUT support */
11751 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
11752 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11753 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
11754 ret, msg.message, msg.wParam);
11755 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
11756
11757 qstatus = GetQueueStatus(qs_all_input);
11758 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11759 "wrong qstatus %08x\n", qstatus);
11760
11761 msg.message = 0;
11762 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
11763 ok(!ret,
11764 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11765 msg.message);
11766 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11767
11768 qstatus = GetQueueStatus(qs_all_input);
11769 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11770 "wrong qstatus %08x\n", qstatus);
11771
11772 msg.message = 0;
11773 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11774 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11775 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11776 ret, msg.message, msg.wParam);
11777 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11778
11779 qstatus = GetQueueStatus(qs_all_input);
11780 ok(qstatus == 0,
11781 "wrong qstatus %08x\n", qstatus);
11782
11783 msg.message = 0;
11784 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11785 ok(!ret,
11786 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11787 msg.message);
11788 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11789
11790 qstatus = GetQueueStatus(qs_all_input);
11791 ok(qstatus == 0,
11792 "wrong qstatus %08x\n", qstatus);
11793
11794 /* test whether presence of the quit flag in the queue affects
11795 * the queue state
11796 */
11797 PostQuitMessage(0x1234abcd);
11798
11799 qstatus = GetQueueStatus(qs_all_input);
11800 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11801 "wrong qstatus %08x\n", qstatus);
11802
11803 PostMessageA(info.hwnd, WM_USER, 0, 0);
11804
11805 qstatus = GetQueueStatus(qs_all_input);
11806 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11807 "wrong qstatus %08x\n", qstatus);
11808
11809 msg.message = 0;
11810 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11811 ok(ret && msg.message == WM_USER,
11812 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
11813 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11814
11815 qstatus = GetQueueStatus(qs_all_input);
11816 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11817 "wrong qstatus %08x\n", qstatus);
11818
11819 msg.message = 0;
11820 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11821 ok(ret && msg.message == WM_QUIT,
11822 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
11823 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
11824 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
11825 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11826
11827 qstatus = GetQueueStatus(qs_all_input);
11828 todo_wine {
11829 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11830 "wrong qstatus %08x\n", qstatus);
11831 }
11832
11833 msg.message = 0;
11834 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11835 ok(!ret,
11836 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11837 msg.message);
11838 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11839
11840 qstatus = GetQueueStatus(qs_all_input);
11841 ok(qstatus == 0,
11842 "wrong qstatus %08x\n", qstatus);
11843
11844 /* some GetMessage tests */
11845
11846 keybd_event('N', 0, 0, 0);
11847 qstatus = GetQueueStatus(qs_all_input);
11848 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11849
11850 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11851 qstatus = GetQueueStatus(qs_all_input);
11852 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11853
11854 if (qstatus)
11855 {
11856 ret = GetMessageA( &msg, 0, 0, 0 );
11857 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11858 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11859 ret, msg.message, msg.wParam);
11860 qstatus = GetQueueStatus(qs_all_input);
11861 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
11862 }
11863
11864 if (qstatus)
11865 {
11866 ret = GetMessageA( &msg, 0, 0, 0 );
11867 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11868 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11869 ret, msg.message, msg.wParam);
11870 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11871 qstatus = GetQueueStatus(qs_all_input);
11872 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11873 }
11874
11875 keybd_event('N', 0, 0, 0);
11876 qstatus = GetQueueStatus(qs_all_input);
11877 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11878
11879 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11880 qstatus = GetQueueStatus(qs_all_input);
11881 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11882
11883 if (qstatus & (QS_KEY << 16))
11884 {
11885 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11886 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11887 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11888 ret, msg.message, msg.wParam);
11889 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
11890 qstatus = GetQueueStatus(qs_all_input);
11891 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11892 }
11893
11894 if (qstatus)
11895 {
11896 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11897 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11898 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11899 ret, msg.message, msg.wParam);
11900 qstatus = GetQueueStatus(qs_all_input);
11901 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11902 }
11903
11904 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11905 qstatus = GetQueueStatus(qs_all_input);
11906 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11907
11908 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11909 qstatus = GetQueueStatus(qs_all_input);
11910 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11911
11912 trace("signalling to send message\n");
11913 SetEvent(info.hevent[EV_SENDMSG]);
11914 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11915 qstatus = GetQueueStatus(qs_all_input);
11916 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11917 "wrong qstatus %08x\n", qstatus);
11918
11919 if (qstatus & (QS_KEY << 16))
11920 {
11921 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11922 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11923 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11924 ret, msg.message, msg.wParam);
11925 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
11926 qstatus = GetQueueStatus(qs_all_input);
11927 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11928 }
11929
11930 if (qstatus)
11931 {
11932 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11933 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11934 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11935 ret, msg.message, msg.wParam);
11936 qstatus = GetQueueStatus(qs_all_input);
11937 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11938 }
11939 done:
11940 trace("signalling to exit\n");
11941 SetEvent(info.hevent[EV_STOP]);
11942
11943 WaitForSingleObject(hthread, INFINITE);
11944
11945 CloseHandle(hthread);
11946 CloseHandle(info.hevent[0]);
11947 CloseHandle(info.hevent[1]);
11948 CloseHandle(info.hevent[2]);
11949
11950 DestroyWindow(info.hwnd);
11951 }
11952
11953 static void wait_move_event(HWND hwnd, int x, int y)
11954 {
11955 MSG msg;
11956 DWORD time;
11957 BOOL ret;
11958
11959 time = GetTickCount();
11960 while (GetTickCount() - time < 200) {
11961 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11962 if (ret && msg.pt.x > x && msg.pt.y > y) break;
11963 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
11964 else Sleep( GetTickCount() - time );
11965 }
11966 }
11967
11968 #define STEP 5
11969 static void test_PeekMessage2(void)
11970 {
11971 HWND hwnd;
11972 BOOL ret;
11973 MSG msg;
11974 UINT message;
11975 DWORD time1, time2, time3;
11976 int x1, y1, x2, y2, x3, y3;
11977 POINT pos;
11978
11979 time1 = time2 = time3 = 0;
11980 x1 = y1 = x2 = y2 = x3 = y3 = 0;
11981
11982 /* Initialise window and make sure it is ready for events */
11983 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
11984 10, 10, 800, 800, NULL, NULL, NULL, NULL);
11985 assert(hwnd);
11986 trace("Window for test_PeekMessage2 %p\n", hwnd);
11987 ShowWindow(hwnd, SW_SHOW);
11988 UpdateWindow(hwnd);
11989 SetFocus(hwnd);
11990 GetCursorPos(&pos);
11991 SetCursorPos(100, 100);
11992 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
11993 flush_events();
11994
11995 /* Do initial mousemove, wait until we can see it
11996 and then do our test peek with PM_NOREMOVE. */
11997 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11998 wait_move_event(hwnd, 100-STEP, 100-STEP);
11999
12000 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12001 if (!ret)
12002 {
12003 skip( "queuing mouse events not supported\n" );
12004 goto done;
12005 }
12006 else
12007 {
12008 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12009 message = msg.message;
12010 time1 = msg.time;
12011 x1 = msg.pt.x;
12012 y1 = msg.pt.y;
12013 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12014 }
12015
12016 /* Allow time to advance a bit, and then simulate the user moving their
12017 * mouse around. After that we peek again with PM_NOREMOVE.
12018 * Although the previous mousemove message was never removed, the
12019 * mousemove we now peek should reflect the recent mouse movements
12020 * because the input queue will merge the move events. */
12021 Sleep(100);
12022 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12023 wait_move_event(hwnd, x1, y1);
12024
12025 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12026 ok(ret, "no message available\n");
12027 if (ret) {
12028 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12029 message = msg.message;
12030 time2 = msg.time;
12031 x2 = msg.pt.x;
12032 y2 = msg.pt.y;
12033 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12034 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12035 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12036 }
12037
12038 /* Have another go, to drive the point home */
12039 Sleep(100);
12040 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12041 wait_move_event(hwnd, x2, y2);
12042
12043 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12044 ok(ret, "no message available\n");
12045 if (ret) {
12046 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12047 message = msg.message;
12048 time3 = msg.time;
12049 x3 = msg.pt.x;
12050 y3 = msg.pt.y;
12051 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12052 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12053 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12054 }
12055
12056 done:
12057 DestroyWindow(hwnd);
12058 SetCursorPos(pos.x, pos.y);
12059 flush_events();
12060 }
12061
12062 static void test_PeekMessage3(void)
12063 {
12064 HWND hwnd;
12065 BOOL ret;
12066 MSG msg;
12067
12068 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12069 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12070 ok(hwnd != NULL, "expected hwnd != NULL\n");
12071 flush_events();
12072
12073 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12074 * were already seen. */
12075
12076 SetTimer(hwnd, 1, 0, NULL);
12077 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12078 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12079 PostMessageA(hwnd, WM_USER, 0, 0);
12080 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12081 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12082 ret = GetMessageA(&msg, NULL, 0, 0);
12083 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12084 ret = GetMessageA(&msg, NULL, 0, 0);
12085 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12086 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12087 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12088
12089 SetTimer(hwnd, 1, 0, NULL);
12090 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12091 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12092 PostMessageA(hwnd, WM_USER, 0, 0);
12093 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12094 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12095 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12096 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12097 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12098 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12099
12100 /* It doesn't matter if a message range is specified or not. */
12101
12102 SetTimer(hwnd, 1, 0, NULL);
12103 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12104 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12105 PostMessageA(hwnd, WM_USER, 0, 0);
12106 ret = GetMessageA(&msg, NULL, 0, 0);
12107 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12108 ret = GetMessageA(&msg, NULL, 0, 0);
12109 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12110 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12111 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12112
12113 /* But not if the post messages were added before the PeekMessage() call. */
12114
12115 PostMessageA(hwnd, WM_USER, 0, 0);
12116 SetTimer(hwnd, 1, 0, NULL);
12117 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12118 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12119 ret = GetMessageA(&msg, NULL, 0, 0);
12120 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12121 ret = GetMessageA(&msg, NULL, 0, 0);
12122 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12123 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12124 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12125
12126 /* More complicated test with multiple messages. */
12127
12128 PostMessageA(hwnd, WM_USER, 0, 0);
12129 SetTimer(hwnd, 1, 0, NULL);
12130 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12131 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12132 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12133 ret = GetMessageA(&msg, NULL, 0, 0);
12134 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12135 ret = GetMessageA(&msg, NULL, 0, 0);
12136 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12137 ret = GetMessageA(&msg, NULL, 0, 0);
12138 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12139 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12140 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12141
12142 /* Newer messages are still returned when specifying a message range. */
12143
12144 SetTimer(hwnd, 1, 0, NULL);
12145 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12146 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12147 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12148 PostMessageA(hwnd, WM_USER, 0, 0);
12149 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
12150 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12151 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE);
12152 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12153 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12154 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12155 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12156 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12157 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12158 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12159 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12160 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12161
12162 /* Also works for posted messages, but the situation is a bit different,
12163 * because both messages are in the same queue. */
12164
12165 PostMessageA(hwnd, WM_TIMER, 0, 0);
12166 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12167 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12168 PostMessageA(hwnd, WM_USER, 0, 0);
12169 ret = GetMessageA(&msg, NULL, 0, 0);
12170 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12171 ret = GetMessageA(&msg, NULL, 0, 0);
12172 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12173 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12174 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12175
12176 PostMessageA(hwnd, WM_USER, 0, 0);
12177 PostMessageA(hwnd, WM_TIMER, 0, 0);
12178 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12179 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12180 ret = GetMessageA(&msg, NULL, 0, 0);
12181 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12182 ret = GetMessageA(&msg, NULL, 0, 0);
12183 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12184 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12185 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12186
12187 DestroyWindow(hwnd);
12188 flush_events();
12189 }
12190
12191 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12192 {
12193 struct recvd_message msg;
12194
12195 if (ignore_message( message )) return 0;
12196
12197 msg.hwnd = hwnd;
12198 msg.message = message;
12199 msg.flags = sent|wparam|lparam;
12200 msg.wParam = wp;
12201 msg.lParam = lp;
12202 msg.descr = "dialog";
12203 add_message(&msg);
12204
12205 switch (message)
12206 {
12207 case WM_INITDIALOG:
12208 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12209 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12210 return 0;
12211
12212 case WM_GETDLGCODE:
12213 return 0;
12214
12215 case WM_USER:
12216 EndDialog(hwnd, 0);
12217 break;
12218 }
12219
12220 return 1;
12221 }
12222
12223 static const struct message WmQuitDialogSeq[] = {
12224 { HCBT_CREATEWND, hook },
12225 { WM_SETFONT, sent },
12226 { WM_INITDIALOG, sent },
12227 { WM_CHANGEUISTATE, sent|optional },
12228 { HCBT_DESTROYWND, hook },
12229 { 0x0090, sent|optional }, /* Vista */
12230 { WM_DESTROY, sent },
12231 { WM_NCDESTROY, sent },
12232 { 0 }
12233 };
12234
12235 static const struct message WmStopQuitSeq[] = {
12236 { WM_DWMNCRENDERINGCHANGED, posted|optional },
12237 { WM_CLOSE, posted },
12238 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12239 { 0 }
12240 };
12241
12242 static void test_quit_message(void)
12243 {
12244 MSG msg;
12245 BOOL ret;
12246
12247 /* test using PostQuitMessage */
12248 flush_events();
12249 PostQuitMessage(0xbeef);
12250
12251 msg.message = 0;
12252 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12253 ok(!ret, "got %x message\n", msg.message);
12254
12255 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12256 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12257 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12258 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12259
12260 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12261 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12262
12263 ret = GetMessageA(&msg, NULL, 0, 0);
12264 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12265 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12266
12267 /* note: WM_QUIT message received after WM_USER message */
12268 ret = GetMessageA(&msg, NULL, 0, 0);
12269 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12270 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12271 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12272
12273 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12274 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12275
12276 /* now test with PostThreadMessage - different behaviour! */
12277 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12278
12279 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12280 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12281 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12282 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12283
12284 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12285 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12286
12287 /* note: we receive the WM_QUIT message first this time */
12288 ret = GetMessageA(&msg, NULL, 0, 0);
12289 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12290 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12291 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12292
12293 ret = GetMessageA(&msg, NULL, 0, 0);
12294 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12295 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12296
12297 flush_events();
12298 flush_sequence();
12299 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12300 ok(ret == 1, "expected 1, got %d\n", ret);
12301 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12302 memset(&msg, 0xab, sizeof(msg));
12303 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12304 ok(ret, "PeekMessage failed\n");
12305 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12306 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12307 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12308
12309 /* Check what happens to a WM_QUIT message posted to a window that gets
12310 * destroyed.
12311 */
12312 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12313 0, 0, 100, 100, NULL, NULL, NULL, NULL);
12314 flush_sequence();
12315 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12316 {
12317 struct recvd_message rmsg;
12318 rmsg.hwnd = msg.hwnd;
12319 rmsg.message = msg.message;
12320 rmsg.flags = posted|wparam|lparam;
12321 rmsg.wParam = msg.wParam;
12322 rmsg.lParam = msg.lParam;
12323 rmsg.descr = "stop/quit";
12324 if (msg.message == WM_QUIT)
12325 /* The hwnd can only be checked here */
12326 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12327 add_message(&rmsg);
12328 DispatchMessageA(&msg);
12329 }
12330 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12331 }
12332
12333 static const struct message WmNotifySeq[] = {
12334 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12335 { 0 }
12336 };
12337
12338 static void test_notify_message(void)
12339 {
12340 HWND hwnd;
12341 BOOL ret;
12342 MSG msg;
12343
12344 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12345 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12346 ok(hwnd != 0, "Failed to create window\n");
12347 flush_events();
12348 flush_sequence();
12349
12350 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12351 ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12352 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12353
12354 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12355 ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12356 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12357
12358 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12359 ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12360 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12361
12362 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12363 ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12364 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12365
12366 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12367 ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12368 flush_events();
12369 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12370
12371 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12372 ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12373 flush_events();
12374 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12375
12376 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12377 ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12378 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12379 {
12380 msg.hwnd = hwnd;
12381 DispatchMessageA(&msg);
12382 }
12383 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12384
12385 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12386 ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12387 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12388 {
12389 msg.hwnd = hwnd;
12390 DispatchMessageA(&msg);
12391 }
12392 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12393
12394 DestroyWindow(hwnd);
12395 }
12396
12397 static const struct message WmMouseHoverSeq[] = {
12398 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12399 { WM_MOUSEACTIVATE, sent|optional },
12400 { WM_TIMER, sent|optional }, /* XP sends it */
12401 { WM_SYSTIMER, sent },
12402 { WM_MOUSEHOVER, sent|wparam, 0 },
12403 { 0 }
12404 };
12405
12406 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12407 {
12408 MSG msg;
12409 DWORD start_ticks, end_ticks;
12410
12411 start_ticks = GetTickCount();
12412 /* add some deviation (50%) to cover not expected delays */
12413 start_ticks += timeout / 2;
12414
12415 do
12416 {
12417 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12418 {
12419 /* Timer proc messages are not dispatched to the window proc,
12420 * and therefore not logged.
12421 */
12422 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12423 {
12424 struct recvd_message s_msg;
12425
12426 s_msg.hwnd = msg.hwnd;
12427 s_msg.message = msg.message;
12428 s_msg.flags = sent|wparam|lparam;
12429 s_msg.wParam = msg.wParam;
12430 s_msg.lParam = msg.lParam;
12431 s_msg.descr = "msg_loop";
12432 add_message(&s_msg);
12433 }
12434 DispatchMessageA(&msg);
12435 }
12436
12437 end_ticks = GetTickCount();
12438
12439 /* inject WM_MOUSEMOVE to see how it changes tracking */
12440 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
12441 {
12442 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12443 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12444
12445 inject_mouse_move = FALSE;
12446 }
12447 } while (start_ticks + timeout >= end_ticks);
12448 }
12449
12450 static void test_TrackMouseEvent(void)
12451 {
12452 TRACKMOUSEEVENT tme;
12453 BOOL ret;
12454 HWND hwnd, hchild;
12455 RECT rc_parent, rc_child;
12456 UINT default_hover_time, hover_width = 0, hover_height = 0;
12457
12458 #define track_hover(track_hwnd, track_hover_time) \
12459 tme.cbSize = sizeof(tme); \
12460 tme.dwFlags = TME_HOVER; \
12461 tme.hwndTrack = track_hwnd; \
12462 tme.dwHoverTime = track_hover_time; \
12463 SetLastError(0xdeadbeef); \
12464 ret = pTrackMouseEvent(&tme); \
12465 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
12466
12467 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
12468 tme.cbSize = sizeof(tme); \
12469 tme.dwFlags = TME_QUERY; \
12470 tme.hwndTrack = (HWND)0xdeadbeef; \
12471 tme.dwHoverTime = 0xdeadbeef; \
12472 SetLastError(0xdeadbeef); \
12473 ret = pTrackMouseEvent(&tme); \
12474 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
12475 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
12476 ok(tme.dwFlags == (expected_track_flags), \
12477 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
12478 ok(tme.hwndTrack == (expected_track_hwnd), \
12479 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
12480 ok(tme.dwHoverTime == (expected_hover_time), \
12481 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
12482
12483 #define track_hover_cancel(track_hwnd) \
12484 tme.cbSize = sizeof(tme); \
12485 tme.dwFlags = TME_HOVER | TME_CANCEL; \
12486 tme.hwndTrack = track_hwnd; \
12487 tme.dwHoverTime = 0xdeadbeef; \
12488 SetLastError(0xdeadbeef); \
12489 ret = pTrackMouseEvent(&tme); \
12490 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12491
12492 default_hover_time = 0xdeadbeef;
12493 SetLastError(0xdeadbeef);
12494 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12495 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12496 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12497 if (!ret) default_hover_time = 400;
12498 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12499
12500 SetLastError(0xdeadbeef);
12501 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12502 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12503 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12504 if (!ret) hover_width = 4;
12505 SetLastError(0xdeadbeef);
12506 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12507 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12508 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12509 if (!ret) hover_height = 4;
12510 trace("hover rect is %u x %d\n", hover_width, hover_height);
12511
12512 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12513 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12514 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12515 NULL, NULL, 0);
12516 assert(hwnd);
12517
12518 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12519 WS_CHILD | WS_BORDER | WS_VISIBLE,
12520 50, 50, 200, 200, hwnd,
12521 NULL, NULL, 0);
12522 assert(hchild);
12523
12524 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12525 flush_events();
12526 flush_sequence();
12527
12528 tme.cbSize = 0;
12529 tme.dwFlags = TME_QUERY;
12530 tme.hwndTrack = (HWND)0xdeadbeef;
12531 tme.dwHoverTime = 0xdeadbeef;
12532 SetLastError(0xdeadbeef);
12533 ret = pTrackMouseEvent(&tme);
12534 ok(!ret, "TrackMouseEvent should fail\n");
12535 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12536 "not expected error %u\n", GetLastError());
12537
12538 tme.cbSize = sizeof(tme);
12539 tme.dwFlags = TME_HOVER;
12540 tme.hwndTrack = (HWND)0xdeadbeef;
12541 tme.dwHoverTime = 0xdeadbeef;
12542 SetLastError(0xdeadbeef);
12543 ret = pTrackMouseEvent(&tme);
12544 ok(!ret, "TrackMouseEvent should fail\n");
12545 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12546 "not expected error %u\n", GetLastError());
12547
12548 tme.cbSize = sizeof(tme);
12549 tme.dwFlags = TME_HOVER | TME_CANCEL;
12550 tme.hwndTrack = (HWND)0xdeadbeef;
12551 tme.dwHoverTime = 0xdeadbeef;
12552 SetLastError(0xdeadbeef);
12553 ret = pTrackMouseEvent(&tme);
12554 ok(!ret, "TrackMouseEvent should fail\n");
12555 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12556 "not expected error %u\n", GetLastError());
12557
12558 GetWindowRect(hwnd, &rc_parent);
12559 GetWindowRect(hchild, &rc_child);
12560 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12561
12562 /* Process messages so that the system updates its internal current
12563 * window and hittest, otherwise TrackMouseEvent calls don't have any
12564 * effect.
12565 */
12566 flush_events();
12567 flush_sequence();
12568
12569 track_query(0, NULL, 0);
12570 track_hover(hchild, 0);
12571 track_query(0, NULL, 0);
12572
12573 flush_events();
12574 flush_sequence();
12575
12576 track_hover(hwnd, 0);
12577 tme.cbSize = sizeof(tme);
12578 tme.dwFlags = TME_QUERY;
12579 tme.hwndTrack = (HWND)0xdeadbeef;
12580 tme.dwHoverTime = 0xdeadbeef;
12581 SetLastError(0xdeadbeef);
12582 ret = pTrackMouseEvent(&tme);
12583 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12584 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12585 if (!tme.dwFlags)
12586 {
12587 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12588 DestroyWindow( hwnd );
12589 return;
12590 }
12591 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12592 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12593 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12594 tme.dwHoverTime, default_hover_time);
12595
12596 pump_msg_loop_timeout(default_hover_time, FALSE);
12597 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12598
12599 track_query(0, NULL, 0);
12600
12601 track_hover(hwnd, HOVER_DEFAULT);
12602 track_query(TME_HOVER, hwnd, default_hover_time);
12603
12604 Sleep(default_hover_time / 2);
12605 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12606 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12607
12608 track_query(TME_HOVER, hwnd, default_hover_time);
12609
12610 pump_msg_loop_timeout(default_hover_time, FALSE);
12611 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12612
12613 track_query(0, NULL, 0);
12614
12615 track_hover(hwnd, HOVER_DEFAULT);
12616 track_query(TME_HOVER, hwnd, default_hover_time);
12617
12618 pump_msg_loop_timeout(default_hover_time, TRUE);
12619 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12620
12621 track_query(0, NULL, 0);
12622
12623 track_hover(hwnd, HOVER_DEFAULT);
12624 track_query(TME_HOVER, hwnd, default_hover_time);
12625 track_hover_cancel(hwnd);
12626
12627 DestroyWindow(hwnd);
12628
12629 #undef track_hover
12630 #undef track_query
12631 #undef track_hover_cancel
12632 }
12633
12634
12635 static const struct message WmSetWindowRgn[] = {
12636 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12637 { WM_NCCALCSIZE, sent|wparam, 1 },
12638 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12639 { WM_GETTEXT, sent|defwinproc|optional },
12640 { WM_ERASEBKGND, sent|optional },
12641 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12642 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12643 { 0 }
12644 };
12645
12646 static const struct message WmSetWindowRgn_no_redraw[] = {
12647 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12648 { WM_NCCALCSIZE, sent|wparam, 1 },
12649 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12650 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12651 { 0 }
12652 };
12653
12654 static const struct message WmSetWindowRgn_clear[] = {
12655 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12656 { WM_NCCALCSIZE, sent|wparam, 1 },
12657 { WM_NCPAINT, sent|optional },
12658 { WM_GETTEXT, sent|defwinproc|optional },
12659 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
12660 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12661 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
12662 { WM_NCPAINT, sent|optional },
12663 { WM_GETTEXT, sent|defwinproc|optional },
12664 { WM_ERASEBKGND, sent|optional },
12665 { WM_WINDOWPOSCHANGING, sent|optional },
12666 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12667 { WM_NCPAINT, sent|optional },
12668 { WM_GETTEXT, sent|defwinproc|optional },
12669 { WM_ERASEBKGND, sent|optional },
12670 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12671 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12672 { WM_NCPAINT, sent|optional },
12673 { WM_GETTEXT, sent|defwinproc|optional },
12674 { WM_ERASEBKGND, sent|optional },
12675 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12676 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12677 { 0 }
12678 };
12679
12680 static void test_SetWindowRgn(void)
12681 {
12682 HRGN hrgn;
12683 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
12684 100, 100, 200, 200, 0, 0, 0, NULL);
12685 ok( hwnd != 0, "Failed to create overlapped window\n" );
12686
12687 ShowWindow( hwnd, SW_SHOW );
12688 UpdateWindow( hwnd );
12689 flush_events();
12690 flush_sequence();
12691
12692 trace("testing SetWindowRgn\n");
12693 hrgn = CreateRectRgn( 0, 0, 150, 150 );
12694 SetWindowRgn( hwnd, hrgn, TRUE );
12695 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
12696
12697 hrgn = CreateRectRgn( 30, 30, 160, 160 );
12698 SetWindowRgn( hwnd, hrgn, FALSE );
12699 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
12700
12701 hrgn = CreateRectRgn( 0, 0, 180, 180 );
12702 SetWindowRgn( hwnd, hrgn, TRUE );
12703 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
12704
12705 SetWindowRgn( hwnd, 0, TRUE );
12706 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
12707
12708 DestroyWindow( hwnd );
12709 }
12710
12711 /*************************** ShowWindow() test ******************************/
12712 static const struct message WmShowNormal[] = {
12713 { WM_SHOWWINDOW, sent|wparam, 1 },
12714 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12715 { HCBT_ACTIVATE, hook },
12716 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12717 { HCBT_SETFOCUS, hook },
12718 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12719 { 0 }
12720 };
12721 static const struct message WmShow[] = {
12722 { WM_SHOWWINDOW, sent|wparam, 1 },
12723 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12724 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12725 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12726 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12727 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12728 { 0 }
12729 };
12730 static const struct message WmShowNoActivate_1[] = {
12731 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12732 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12733 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12734 { WM_MOVE, sent|defwinproc|optional },
12735 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12736 { 0 }
12737 };
12738 static const struct message WmShowNoActivate_2[] = {
12739 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12740 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12741 { HCBT_ACTIVATE, hook|optional },
12742 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12743 { HCBT_SETFOCUS, hook|optional },
12744 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12745 { WM_MOVE, sent|defwinproc },
12746 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12747 { HCBT_SETFOCUS, hook|optional },
12748 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12749 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12750 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12751 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12752 { 0 }
12753 };
12754 static const struct message WmShowNA_1[] = {
12755 { WM_SHOWWINDOW, sent|wparam, 1 },
12756 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12757 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12758 { 0 }
12759 };
12760 static const struct message WmShowNA_2[] = {
12761 { WM_SHOWWINDOW, sent|wparam, 1 },
12762 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12763 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12764 { 0 }
12765 };
12766 static const struct message WmRestore_1[] = {
12767 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12768 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12769 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12770 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12771 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12772 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12773 { WM_MOVE, sent|defwinproc },
12774 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12775 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12776 { 0 }
12777 };
12778 static const struct message WmRestore_2[] = {
12779 { WM_SHOWWINDOW, sent|wparam, 1 },
12780 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12781 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12782 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12783 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12784 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12785 { 0 }
12786 };
12787 static const struct message WmRestore_3[] = {
12788 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12789 { WM_GETMINMAXINFO, sent },
12790 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12791 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12792 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12793 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12794 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12795 { WM_MOVE, sent|defwinproc },
12796 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12797 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12798 { 0 }
12799 };
12800 static const struct message WmRestore_4[] = {
12801 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
12802 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12803 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12804 { WM_MOVE, sent|defwinproc|optional },
12805 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12806 { 0 }
12807 };
12808 static const struct message WmRestore_5[] = {
12809 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
12810 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12811 { HCBT_ACTIVATE, hook|optional },
12812 { HCBT_SETFOCUS, hook|optional },
12813 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12814 { WM_MOVE, sent|defwinproc|optional },
12815 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12816 { 0 }
12817 };
12818 static const struct message WmHide_1[] = {
12819 { WM_SHOWWINDOW, sent|wparam, 0 },
12820 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
12821 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
12822 { HCBT_ACTIVATE, hook|optional },
12823 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12824 { 0 }
12825 };
12826 static const struct message WmHide_2[] = {
12827 { WM_SHOWWINDOW, sent|wparam, 0 },
12828 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12829 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12830 { HCBT_ACTIVATE, hook|optional },
12831 { 0 }
12832 };
12833 static const struct message WmHide_3[] = {
12834 { WM_SHOWWINDOW, sent|wparam, 0 },
12835 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12836 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12837 { HCBT_SETFOCUS, hook|optional },
12838 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12839 { 0 }
12840 };
12841 static const struct message WmShowMinimized_1[] = {
12842 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12843 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12844 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12845 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12846 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12847 { WM_MOVE, sent|defwinproc },
12848 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12849 { 0 }
12850 };
12851 static const struct message WmMinimize_1[] = {
12852 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12853 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12854 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12855 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12856 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12857 { WM_MOVE, sent|defwinproc },
12858 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12859 { 0 }
12860 };
12861 static const struct message WmMinimize_2[] = {
12862 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12863 { HCBT_SETFOCUS, hook|optional },
12864 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12865 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12866 { WM_MOVE, sent|defwinproc },
12867 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12868 { 0 }
12869 };
12870 static const struct message WmMinimize_3[] = {
12871 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12872 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12873 { HCBT_ACTIVATE, hook|optional },
12874 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12875 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12876 { WM_MOVE, sent|defwinproc },
12877 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12878 { 0 }
12879 };
12880 static const struct message WmShowMinNoActivate[] = {
12881 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12882 { WM_WINDOWPOSCHANGING, sent },
12883 { WM_WINDOWPOSCHANGED, sent },
12884 { WM_MOVE, sent|defwinproc|optional },
12885 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12886 { 0 }
12887 };
12888 static const struct message WmMinMax_1[] = {
12889 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12890 { 0 }
12891 };
12892 static const struct message WmMinMax_2[] = {
12893 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12894 { WM_GETMINMAXINFO, sent|optional },
12895 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
12896 { HCBT_ACTIVATE, hook|optional },
12897 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12898 { HCBT_SETFOCUS, hook|optional },
12899 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12900 { WM_MOVE, sent|defwinproc|optional },
12901 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
12902 { HCBT_SETFOCUS, hook|optional },
12903 { 0 }
12904 };
12905 static const struct message WmMinMax_3[] = {
12906 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12907 { HCBT_SETFOCUS, hook|optional },
12908 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12909 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12910 { WM_MOVE, sent|defwinproc|optional },
12911 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12912 { 0 }
12913 };
12914 static const struct message WmMinMax_4[] = {
12915 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12916 { 0 }
12917 };
12918 static const struct message WmShowMaximized_1[] = {
12919 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12920 { WM_GETMINMAXINFO, sent },
12921 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12922 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12923 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12924 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12925 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12926 { WM_MOVE, sent|defwinproc },
12927 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12928 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12929 { 0 }
12930 };
12931 static const struct message WmShowMaximized_2[] = {
12932 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12933 { WM_GETMINMAXINFO, sent },
12934 { WM_WINDOWPOSCHANGING, sent|optional },
12935 { HCBT_ACTIVATE, hook|optional },
12936 { WM_WINDOWPOSCHANGED, sent|optional },
12937 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
12938 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
12939 { WM_WINDOWPOSCHANGING, sent|optional },
12940 { HCBT_SETFOCUS, hook|optional },
12941 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12942 { WM_MOVE, sent|defwinproc },
12943 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12944 { HCBT_SETFOCUS, hook|optional },
12945 { 0 }
12946 };
12947 static const struct message WmShowMaximized_3[] = {
12948 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12949 { WM_GETMINMAXINFO, sent|optional },
12950 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12951 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12952 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12953 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12954 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12955 { WM_MOVE, sent|defwinproc|optional },
12956 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12957 { 0 }
12958 };
12959
12960 static void test_ShowWindow(void)
12961 {
12962 /* ShowWindow commands in random order */
12963 static const struct
12964 {
12965 INT cmd; /* ShowWindow command */
12966 LPARAM ret; /* ShowWindow return value */
12967 DWORD style; /* window style after the command */
12968 const struct message *msg; /* message sequence the command produces */
12969 INT wp_cmd, wp_flags; /* window placement after the command */
12970 POINT wp_min, wp_max; /* window placement after the command */
12971 BOOL todo_msg; /* message sequence doesn't match what Wine does */
12972 } sw[] =
12973 {
12974 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
12975 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12976 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
12977 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12978 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
12979 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12980 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12981 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12982 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
12983 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12984 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
12985 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12986 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
12987 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12988 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12989 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12990 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
12991 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12992 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
12993 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12994 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
12995 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12996 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
12997 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12998 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
12999 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13000 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13001 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13002 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
13003 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13004 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13005 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13006 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
13007 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13008 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13009 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13010 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13011 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13012 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13013 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13014 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13015 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13016 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13017 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13018 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13019 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13020 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13021 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13022 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13023 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13024 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13025 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13026 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13027 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13028 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13029 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13030 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13031 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13032 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13033 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13034 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13035 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13036 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13037 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13038 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13039 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13040 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13041 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13042 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13043 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13044 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13045 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13046 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13047 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13048 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13049 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13050 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13051 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13052 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13053 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13054 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13055 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13056 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13057 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13058 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13059 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13060 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13061 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13062 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13063 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13064 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13065 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13066 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13067 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13068 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13069 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13070 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13071 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13072 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13073 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13074 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13075 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13076 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13077 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13078 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13079 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13080 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13081 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13082 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13083 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13084 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13085 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13086 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13087 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13088 };
13089 HWND hwnd;
13090 DWORD style;
13091 LPARAM ret;
13092 INT i;
13093 WINDOWPLACEMENT wp;
13094 RECT win_rc, work_rc = {0, 0, 0, 0};
13095
13096 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13097 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13098 120, 120, 90, 90,
13099 0, 0, 0, NULL);
13100 assert(hwnd);
13101
13102 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13103 ok(style == 0, "expected style 0, got %08x\n", style);
13104
13105 flush_events();
13106 flush_sequence();
13107
13108 if (pGetMonitorInfoA && pMonitorFromPoint)
13109 {
13110 HMONITOR hmon;
13111 MONITORINFO mi;
13112 POINT pt = {0, 0};
13113
13114 SetLastError(0xdeadbeef);
13115 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13116 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13117
13118 mi.cbSize = sizeof(mi);
13119 SetLastError(0xdeadbeef);
13120 ret = pGetMonitorInfoA(hmon, &mi);
13121 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13122 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13123 wine_dbgstr_rect(&mi.rcWork));
13124 work_rc = mi.rcWork;
13125 }
13126
13127 GetWindowRect(hwnd, &win_rc);
13128 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13129
13130 wp.length = sizeof(wp);
13131 SetLastError(0xdeadbeaf);
13132 ret = GetWindowPlacement(hwnd, &wp);
13133 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13134 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13135 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13136 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13137 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13138 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13139 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13140 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13141 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13142 wine_dbgstr_rect(&wp.rcNormalPosition));
13143
13144 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
13145 {
13146 static const char * const sw_cmd_name[13] =
13147 {
13148 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13149 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13150 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13151 "SW_NORMALNA" /* 0xCC */
13152 };
13153 char comment[64];
13154 INT idx; /* index into the above array of names */
13155
13156 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13157
13158 style = GetWindowLongA(hwnd, GWL_STYLE);
13159 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13160 ret = ShowWindow(hwnd, sw[i].cmd);
13161 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13162 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13163 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13164
13165 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13166 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13167
13168 wp.length = sizeof(wp);
13169 SetLastError(0xdeadbeaf);
13170 ret = GetWindowPlacement(hwnd, &wp);
13171 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13172 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13173 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13174
13175 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13176 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13177 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13178 {
13179 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13180 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13181 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13182 }
13183 else
13184 {
13185 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13186 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13187 }
13188
13189 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13190 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13191 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13192
13193 if (0) /* FIXME: Wine behaves completely different here */
13194 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13195 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13196 }
13197 DestroyWindow(hwnd);
13198 flush_events();
13199 }
13200
13201 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13202 {
13203 struct recvd_message msg;
13204
13205 if (ignore_message( message )) return 0;
13206
13207 msg.hwnd = hwnd;
13208 msg.message = message;
13209 msg.flags = sent|wparam|lparam;
13210 msg.wParam = wParam;
13211 msg.lParam = lParam;
13212 msg.descr = "dialog";
13213 add_message(&msg);
13214
13215 /* calling DefDlgProc leads to a recursion under XP */
13216
13217 switch (message)
13218 {
13219 case WM_INITDIALOG:
13220 return lParam;
13221
13222 case WM_GETDLGCODE:
13223 return 0;
13224 }
13225 return 1;
13226 }
13227
13228 static WNDPROC orig_edit_proc;
13229 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13230 {
13231 struct recvd_message msg;
13232
13233 if (ignore_message( message )) return 0;
13234
13235 msg.hwnd = hwnd;
13236 msg.message = message;
13237 msg.flags = sent|wparam|lparam;
13238 msg.wParam = wp;
13239 msg.lParam = lp;
13240 msg.descr = "edit";
13241 add_message(&msg);
13242
13243 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13244 }
13245
13246 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13247 {
13248 struct recvd_message msg;
13249
13250 if (ignore_message( message )) return 0;
13251
13252 msg.hwnd = hwnd;
13253 msg.message = message;
13254 msg.flags = sent|wparam|lparam|parent;
13255 msg.wParam = wParam;
13256 msg.lParam = lParam;
13257 msg.descr = "dialog";
13258 add_message(&msg);
13259
13260 if (message == WM_INITDIALOG)
13261 {
13262 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13263 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13264 }
13265
13266 return 1;
13267 }
13268
13269 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13270 {
13271 ok( 0, "should not be called since DefDlgProc is not used\n" );
13272 return 0;
13273 }
13274
13275 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13276 {
13277 struct recvd_message msg;
13278
13279 if (!ignore_message( message ))
13280 {
13281 msg.hwnd = hwnd;
13282 msg.message = message;
13283 msg.flags = sent|wparam|lparam|parent;
13284 msg.wParam = wParam;
13285 msg.lParam = lParam;
13286 msg.descr = "dialog";
13287 add_message(&msg);
13288 }
13289 if (message == WM_INITDIALOG)
13290 {
13291 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13292 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13293 return 1;
13294 }
13295 return DefWindowProcW( hwnd, message, wParam, lParam );
13296 }
13297
13298 static const struct message WmDefDlgSetFocus_1[] = {
13299 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13300 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13301 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13302 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13303 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13304 { HCBT_SETFOCUS, hook },
13305 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13306 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13307 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13308 { WM_SETFOCUS, sent|wparam, 0 },
13309 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13310 { WM_CTLCOLOREDIT, sent },
13311 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13312 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13313 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13314 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13315 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13316 { 0 }
13317 };
13318 static const struct message WmDefDlgSetFocus_2[] = {
13319 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13320 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13321 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13322 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13323 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13324 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13325 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13326 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13327 { 0 }
13328 };
13329 /* Creation of a dialog */
13330 static const struct message WmCreateDialogParamSeq_0[] = {
13331 { HCBT_CREATEWND, hook },
13332 { WM_NCCREATE, sent },
13333 { WM_NCCALCSIZE, sent|wparam, 0 },
13334 { WM_CREATE, sent },
13335 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13336 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13337 { WM_MOVE, sent },
13338 { WM_SETFONT, sent },
13339 { WM_INITDIALOG, sent },
13340 { WM_CHANGEUISTATE, sent|optional },
13341 { 0 }
13342 };
13343 /* Creation of a dialog */
13344 static const struct message WmCreateDialogParamSeq_1[] = {
13345 { HCBT_CREATEWND, hook },
13346 { WM_NCCREATE, sent },
13347 { WM_NCCALCSIZE, sent|wparam, 0 },
13348 { WM_CREATE, sent },
13349 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13350 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13351 { WM_MOVE, sent },
13352 { WM_SETFONT, sent },
13353 { WM_INITDIALOG, sent },
13354 { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13355 { HCBT_SETFOCUS, hook },
13356 { HCBT_ACTIVATE, hook },
13357 { WM_QUERYNEWPALETTE, sent|optional },
13358 { WM_PALETTEISCHANGING, sent|optional },
13359 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13360 { WM_ACTIVATEAPP, sent|wparam, 1 },
13361 { WM_NCACTIVATE, sent },
13362 { WM_ACTIVATE, sent|wparam, 1 },
13363 { WM_SETFOCUS, sent },
13364 { WM_CHANGEUISTATE, sent|optional },
13365 { 0 }
13366 };
13367 /* Creation of a dialog */
13368 static const struct message WmCreateDialogParamSeq_2[] = {
13369 { HCBT_CREATEWND, hook },
13370 { WM_NCCREATE, sent },
13371 { WM_NCCALCSIZE, sent|wparam, 0 },
13372 { WM_CREATE, sent },
13373 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13374 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13375 { WM_MOVE, sent },
13376 { WM_CHANGEUISTATE, sent|optional },
13377 { 0 }
13378 };
13379
13380 static const struct message WmCreateDialogParamSeq_3[] = {
13381 { HCBT_CREATEWND, hook },
13382 { WM_SETFONT, sent|parent },
13383 { WM_INITDIALOG, sent|parent },
13384 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13385 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13386 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13387 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13388 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13389 { HCBT_ACTIVATE, hook },
13390 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13391 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13392 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13393 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13394 { WM_NCACTIVATE, sent|parent },
13395 { WM_ACTIVATE, sent|parent|wparam, 1 },
13396 { WM_SETFOCUS, sent },
13397 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13398 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13399 { WM_USER, sent|parent },
13400 { WM_CHANGEUISTATE, sent|parent|optional },
13401 { 0 }
13402 };
13403
13404 static const struct message WmCreateDialogParamSeq_4[] = {
13405 { HCBT_CREATEWND, hook },
13406 { WM_NCCREATE, sent|parent },
13407 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13408 { WM_CREATE, sent|parent },
13409 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13410 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13411 { WM_MOVE, sent|parent },
13412 { WM_SETFONT, sent|parent },
13413 { WM_INITDIALOG, sent|parent },
13414 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13415 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13416 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13417 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13418 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13419 { HCBT_ACTIVATE, hook },
13420 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13421 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13422 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13423 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13424 { WM_NCACTIVATE, sent|parent },
13425 { WM_ACTIVATE, sent|parent|wparam, 1 },
13426 { HCBT_SETFOCUS, hook },
13427 { WM_SETFOCUS, sent|parent },
13428 { WM_KILLFOCUS, sent|parent },
13429 { WM_SETFOCUS, sent },
13430 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13431 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13432 { WM_USER, sent|parent },
13433 { WM_CHANGEUISTATE, sent|parent|optional },
13434 { WM_UPDATEUISTATE, sent|parent|optional },
13435 { WM_UPDATEUISTATE, sent|optional },
13436 { 0 }
13437 };
13438
13439 static void test_dialog_messages(void)
13440 {
13441 WNDCLASSA cls;
13442 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
13443 LRESULT ret;
13444
13445 #define set_selection(hctl, start, end) \
13446 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
13447 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
13448
13449 #define check_selection(hctl, start, end) \
13450 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
13451 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
13452
13453 subclass_edit();
13454
13455 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
13456 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13457 0, 0, 100, 100, 0, 0, 0, NULL);
13458 ok(hdlg != 0, "Failed to create custom dialog window\n");
13459
13460 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
13461 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13462 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
13463 ok(hedit1 != 0, "Failed to create edit control\n");
13464 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
13465 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13466 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
13467 ok(hedit2 != 0, "Failed to create edit control\n");
13468
13469 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
13470 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
13471
13472 hfocus = GetFocus();
13473 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13474
13475 SetFocus(hedit2);
13476 hfocus = GetFocus();
13477 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
13478
13479 check_selection(hedit1, 0, 0);
13480 check_selection(hedit2, 0, 0);
13481
13482 set_selection(hedit2, 0, -1);
13483 check_selection(hedit2, 0, 3);
13484
13485 SetFocus(0);
13486 hfocus = GetFocus();
13487 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13488
13489 flush_sequence();
13490 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13491 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13492 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
13493
13494 hfocus = GetFocus();
13495 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13496
13497 check_selection(hedit1, 0, 5);
13498 check_selection(hedit2, 0, 3);
13499
13500 flush_sequence();
13501 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13502 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13503 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
13504
13505 hfocus = GetFocus();
13506 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13507
13508 check_selection(hedit1, 0, 5);
13509 check_selection(hedit2, 0, 3);
13510
13511 EndDialog(hdlg, 0);
13512 DestroyWindow(hedit1);
13513 DestroyWindow(hedit2);
13514 DestroyWindow(hdlg);
13515 flush_sequence();
13516
13517 #undef set_selection
13518 #undef check_selection
13519
13520 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13521 cls.lpszClassName = "MyDialogClass";
13522 cls.hInstance = GetModuleHandleA(NULL);
13523 /* need a cast since a dlgproc is used as a wndproc */
13524 cls.lpfnWndProc = test_dlg_proc;
13525 if (!RegisterClassA(&cls)) assert(0);
13526
13527 SetFocus(0);
13528 flush_sequence();
13529 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13530 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13531 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
13532 hfocus = GetFocus();
13533 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13534 EndDialog(hdlg, 0);
13535 DestroyWindow(hdlg);
13536 flush_sequence();
13537
13538 SetFocus(0);
13539 flush_sequence();
13540 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
13541 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13542 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13543 hfocus = GetFocus();
13544 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13545 EndDialog(hdlg, 0);
13546 DestroyWindow(hdlg);
13547 flush_sequence();
13548
13549 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13550 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13551 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13552 EndDialog(hdlg, 0);
13553 DestroyWindow(hdlg);
13554 flush_sequence();
13555
13556 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13557 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13558 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13559 EndDialog(hdlg, 0);
13560 DestroyWindow(hdlg);
13561 flush_sequence();
13562
13563 UnregisterClassA( cls.lpszClassName, cls.hInstance );
13564 cls.lpfnWndProc = test_dlg_proc4;
13565 ok( RegisterClassA(&cls), "failed to register class again\n" );
13566 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13567 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13568 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13569 EndDialog(hdlg, 0);
13570 DestroyWindow(hdlg);
13571 flush_sequence();
13572
13573 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13574
13575 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13576 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13577 100, 100, 200, 200, 0, 0, 0, NULL);
13578 ok (parent != 0, "Failed to create parent window\n");
13579
13580 /* This child has no parent set. We will later call SetParent on it,
13581 * so that it will have a parent set, but no WS_CHILD style. */
13582 child = CreateWindowExA(0, "TestWindowClass", "Test child",
13583 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13584 100, 100, 200, 200, 0, 0, 0, NULL);
13585 ok (child != 0, "Failed to create child window\n");
13586
13587 /* This is a regular child window. When used as an owner, the other
13588 * child window will be used. */
13589 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13590 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13591 100, 100, 200, 200, child, 0, 0, NULL);
13592 ok (child2 != 0, "Failed to create child window\n");
13593
13594 SetParent(child, parent);
13595 SetFocus(child);
13596
13597 flush_sequence();
13598 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13599 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13600
13601 DestroyWindow(child2);
13602 DestroyWindow(child);
13603 DestroyWindow(parent);
13604 flush_sequence();
13605 }
13606
13607 static void test_enddialog_seq(HWND dialog, HWND owner)
13608 {
13609 const struct message seq[] = {
13610 { WM_ENABLE, sent },
13611 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13612 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13613 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13614 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13615 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13616 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13617 { WM_QUERYNEWPALETTE, sent|optional },
13618 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13619 { WM_GETTEXT, sent|optional|defwinproc },
13620 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13621 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13622 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13623 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13624 { 0 }
13625 };
13626
13627 flush_sequence();
13628 EndDialog(dialog, 0);
13629 ok_sequence(seq, "EndDialog", FALSE);
13630 }
13631
13632 static void test_enddialog_seq2(HWND dialog, HWND owner)
13633 {
13634 const struct message seq[] = {
13635 { WM_ENABLE, parent|sent },
13636 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13637 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13638 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13639 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13640 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13641 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13642 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13643 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13644 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13645 { 0 }
13646 };
13647
13648 flush_sequence();
13649 EndDialog(dialog, 0);
13650 ok_sequence(seq, "EndDialog2", FALSE);
13651 }
13652
13653 static void test_EndDialog(void)
13654 {
13655 HWND hparent, hother, hactive, hdlg, hchild;
13656 WNDCLASSA cls;
13657
13658 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13659 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13660 100, 100, 200, 200, 0, 0, 0, NULL);
13661 ok (hparent != 0, "Failed to create parent window\n");
13662
13663 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
13664 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13665 200, 100, 200, 200, 0, 0, 0, NULL);
13666 ok (hother != 0, "Failed to create parent window\n");
13667
13668 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13669 cls.lpszClassName = "MyDialogClass";
13670 cls.hInstance = GetModuleHandleA(NULL);
13671 cls.lpfnWndProc = test_dlg_proc;
13672 if (!RegisterClassA(&cls)) assert(0);
13673
13674 flush_sequence();
13675 SetForegroundWindow(hother);
13676 hactive = GetForegroundWindow();
13677 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
13678
13679 /* create a dialog where the parent is disabled, this parent should be
13680 * enabled and receive focus when dialog exits */
13681 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
13682 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13683 SetForegroundWindow(hdlg);
13684 hactive = GetForegroundWindow();
13685 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
13686 EndDialog(hdlg, 0);
13687 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13688 hactive = GetForegroundWindow();
13689 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13690 DestroyWindow(hdlg);
13691 flush_sequence();
13692
13693 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
13694 EnableWindow(hparent, FALSE);
13695 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
13696 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13697 0, 0, 100, 100, hparent, 0, 0, NULL);
13698 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13699 flush_sequence();
13700 SetForegroundWindow(hother);
13701 flush_sequence();
13702 hactive = GetForegroundWindow();
13703 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
13704 hactive = GetActiveWindow();
13705 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
13706 EndDialog(hdlg, 0);
13707 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13708 hactive = GetForegroundWindow();
13709 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13710 DestroyWindow(hdlg);
13711 flush_sequence();
13712
13713 DestroyWindow( hparent );
13714
13715 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13716 WS_POPUP | WS_VISIBLE | WS_DISABLED,
13717 100, 100, 200, 200, 0, 0, 0, NULL);
13718 ok (hparent != 0, "Failed to create parent window\n");
13719
13720 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
13721 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13722 0, 0, 0, 0, 0, 0, 0, NULL);
13723 ok (hchild != 0, "Failed to create child window\n");
13724
13725 SetParent(hchild, hparent);
13726
13727 flush_sequence();
13728 SetForegroundWindow(hother);
13729 hactive = GetForegroundWindow();
13730 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13731
13732 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13733 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13734
13735 SetForegroundWindow(hdlg);
13736 test_enddialog_seq(hdlg, hchild);
13737
13738 hactive = GetForegroundWindow();
13739 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13740
13741 DestroyWindow(hdlg);
13742
13743 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
13744 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
13745
13746 SetForegroundWindow(hother);
13747 hactive = GetForegroundWindow();
13748 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13749
13750 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13751 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13752
13753 SetForegroundWindow(hdlg);
13754 test_enddialog_seq2(hdlg, hparent);
13755
13756 hactive = GetForegroundWindow();
13757 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13758 DestroyWindow(hdlg);
13759 DestroyWindow(hchild);
13760 DestroyWindow(hparent);
13761 DestroyWindow(hother);
13762 flush_sequence();
13763
13764 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13765 }
13766
13767 static void test_nullCallback(void)
13768 {
13769 HWND hwnd;
13770
13771 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13772 100, 100, 200, 200, 0, 0, 0, NULL);
13773 ok (hwnd != 0, "Failed to create overlapped window\n");
13774
13775 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
13776 flush_events();
13777 DestroyWindow(hwnd);
13778 }
13779
13780 /* SetActiveWindow( 0 ) hwnd visible */
13781 static const struct message SetActiveWindowSeq0[] =
13782 {
13783 { HCBT_ACTIVATE, hook|optional },
13784 { WM_NCACTIVATE, sent|wparam, 0 },
13785 { WM_GETTEXT, sent|defwinproc|optional },
13786 { WM_ACTIVATE, sent|wparam, 0 },
13787 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13788 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13789 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13790 { WM_KILLFOCUS, sent|optional },
13791 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13792 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13793 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13794 { WM_GETTEXT, sent|defwinproc|optional },
13795 { WM_ACTIVATE, sent|wparam|optional, 1 },
13796 { HCBT_SETFOCUS, hook|optional },
13797 { WM_KILLFOCUS, sent|defwinproc|optional },
13798 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13799 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13800 { WM_IME_SETCONTEXT, sent|optional },
13801 { WM_IME_SETCONTEXT, sent|optional },
13802 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13803 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13804 { WM_SETFOCUS, sent|defwinproc|optional },
13805 { WM_GETTEXT, sent|optional },
13806 { 0 }
13807 };
13808 /* SetActiveWindow( hwnd ) hwnd visible */
13809 static const struct message SetActiveWindowSeq1[] =
13810 {
13811 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13812 { 0 }
13813 };
13814 /* SetActiveWindow( popup ) hwnd visible, popup visible */
13815 static const struct message SetActiveWindowSeq2[] =
13816 {
13817 { HCBT_ACTIVATE, hook },
13818 { WM_NCACTIVATE, sent|wparam, 0 },
13819 { WM_GETTEXT, sent|defwinproc|optional },
13820 { WM_ACTIVATE, sent|wparam, 0 },
13821 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13822 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13823 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13824 { WM_NCPAINT, sent|optional },
13825 { WM_GETTEXT, sent|defwinproc|optional },
13826 { WM_ERASEBKGND, sent|optional },
13827 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13828 { WM_NCACTIVATE, sent|wparam, 1 },
13829 { WM_GETTEXT, sent|defwinproc|optional },
13830 { WM_ACTIVATE, sent|wparam, 1 },
13831 { HCBT_SETFOCUS, hook },
13832 { WM_KILLFOCUS, sent|defwinproc },
13833 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13834 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13835 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13836 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13837 { WM_SETFOCUS, sent|defwinproc },
13838 { WM_GETTEXT, sent|optional },
13839 { 0 }
13840 };
13841
13842 /* SetActiveWindow( hwnd ) hwnd not visible */
13843 static const struct message SetActiveWindowSeq3[] =
13844 {
13845 { HCBT_ACTIVATE, hook },
13846 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13847 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13848 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13849 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13850 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13851 { WM_ACTIVATEAPP, sent|wparam, 1 },
13852 { WM_ACTIVATEAPP, sent|wparam, 1 },
13853 { WM_NCACTIVATE, sent|wparam, 1 },
13854 { WM_ACTIVATE, sent|wparam, 1 },
13855 { HCBT_SETFOCUS, hook },
13856 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13857 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13858 { WM_SETFOCUS, sent|defwinproc },
13859 { 0 }
13860 };
13861 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
13862 static const struct message SetActiveWindowSeq4[] =
13863 {
13864 { HCBT_ACTIVATE, hook },
13865 { WM_NCACTIVATE, sent|wparam, 0 },
13866 { WM_GETTEXT, sent|defwinproc|optional },
13867 { WM_ACTIVATE, sent|wparam, 0 },
13868 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13869 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13870 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13871 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13872 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13873 { WM_NCACTIVATE, sent|wparam, 1 },
13874 { WM_GETTEXT, sent|defwinproc|optional },
13875 { WM_ACTIVATE, sent|wparam, 1 },
13876 { HCBT_SETFOCUS, hook },
13877 { WM_KILLFOCUS, sent|defwinproc },
13878 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13879 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13880 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13881 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13882 { WM_SETFOCUS, sent|defwinproc },
13883 { 0 }
13884 };
13885
13886
13887 static void test_SetActiveWindow(void)
13888 {
13889 HWND hwnd, popup, ret;
13890
13891 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13892 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13893 100, 100, 200, 200, 0, 0, 0, NULL);
13894
13895 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13896 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
13897 100, 100, 200, 200, hwnd, 0, 0, NULL);
13898
13899 ok(hwnd != 0, "Failed to create overlapped window\n");
13900 ok(popup != 0, "Failed to create popup window\n");
13901 SetForegroundWindow( popup );
13902 flush_sequence();
13903
13904 trace("SetActiveWindow(0)\n");
13905 ret = SetActiveWindow(0);
13906 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
13907 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
13908 flush_sequence();
13909
13910 trace("SetActiveWindow(hwnd), hwnd visible\n");
13911 ret = SetActiveWindow(hwnd);
13912 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
13913 flush_sequence();
13914
13915 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
13916 ret = SetActiveWindow(popup);
13917 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
13918 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
13919 flush_sequence();
13920
13921 ShowWindow(hwnd, SW_HIDE);
13922 ShowWindow(popup, SW_HIDE);
13923 flush_sequence();
13924
13925 trace("SetActiveWindow(hwnd), hwnd not visible\n");
13926 ret = SetActiveWindow(hwnd);
13927 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
13928 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
13929 flush_sequence();
13930
13931 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
13932 ret = SetActiveWindow(popup);
13933 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
13934 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
13935 flush_sequence();
13936
13937 trace("done\n");
13938
13939 DestroyWindow(hwnd);
13940 }
13941
13942 static const struct message SetForegroundWindowSeq[] =
13943 {
13944 { WM_NCACTIVATE, sent|wparam, 0 },
13945 { WM_GETTEXT, sent|defwinproc|optional },
13946 { WM_ACTIVATE, sent|wparam, 0 },
13947 { WM_ACTIVATEAPP, sent|wparam, 0 },
13948 { WM_KILLFOCUS, sent },
13949 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
13950 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
13951 { 0 }
13952 };
13953
13954 static void test_SetForegroundWindow(void)
13955 {
13956 HWND hwnd;
13957
13958 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
13959 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13960 100, 100, 200, 200, 0, 0, 0, NULL);
13961 ok (hwnd != 0, "Failed to create overlapped window\n");
13962 SetForegroundWindow( hwnd );
13963 flush_sequence();
13964
13965 trace("SetForegroundWindow( 0 )\n");
13966 SetForegroundWindow( 0 );
13967 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
13968 trace("SetForegroundWindow( GetDesktopWindow() )\n");
13969 SetForegroundWindow( GetDesktopWindow() );
13970 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
13971 "foreground top level window", FALSE);
13972 trace("done\n");
13973
13974 DestroyWindow(hwnd);
13975 }
13976
13977 static DWORD get_input_codepage( void )
13978 {
13979 DWORD cp;
13980 int ret;
13981 HKL hkl = GetKeyboardLayout( 0 );
13982
13983 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
13984 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
13985 if (!ret) cp = CP_ACP;
13986 return cp;
13987 }
13988
13989 static void test_dbcs_wm_char(void)
13990 {
13991 BYTE dbch[2];
13992 WCHAR wch, bad_wch;
13993 HWND hwnd, hwnd2;
13994 MSG msg;
13995 DWORD time;
13996 POINT pt;
13997 DWORD_PTR res;
13998 CPINFOEXA cpinfo;
13999 UINT i, j, k;
14000 struct message wmCharSeq[2];
14001 BOOL ret;
14002 DWORD cp = get_input_codepage();
14003
14004 if (!pGetCPInfoExA)
14005 {
14006 win_skip("GetCPInfoExA is not available\n");
14007 return;
14008 }
14009
14010 pGetCPInfoExA( cp, 0, &cpinfo );
14011 if (cpinfo.MaxCharSize != 2)
14012 {
14013 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14014 return;
14015 }
14016
14017 dbch[0] = dbch[1] = 0;
14018 wch = 0;
14019 bad_wch = cpinfo.UnicodeDefaultChar;
14020 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14021 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14022 for (k = 128; k <= 255; k++)
14023 {
14024 char str[2];
14025 WCHAR wstr[2];
14026 str[0] = j;
14027 str[1] = k;
14028 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14029 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14030 (BYTE)str[0] == j && (BYTE)str[1] == k &&
14031 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14032 {
14033 dbch[0] = j;
14034 dbch[1] = k;
14035 wch = wstr[0];
14036 break;
14037 }
14038 }
14039
14040 if (!wch)
14041 {
14042 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14043 return;
14044 }
14045 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14046 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14047
14048 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14049 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14050 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14051 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14052 ok (hwnd != 0, "Failed to create overlapped window\n");
14053 ok (hwnd2 != 0, "Failed to create overlapped window\n");
14054 flush_sequence();
14055
14056 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14057 wmCharSeq[0].message = WM_CHAR;
14058 wmCharSeq[0].flags = sent|wparam;
14059 wmCharSeq[0].wParam = wch;
14060
14061 /* posted message */
14062 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14063 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14064 ok( !ret, "got message %x\n", msg.message );
14065 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14066 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14067 ok( ret, "no message\n" );
14068 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14069 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14070 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14071 ok( !ret, "got message %x\n", msg.message );
14072
14073 /* posted thread message */
14074 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14075 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14076 ok( !ret, "got message %x\n", msg.message );
14077 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14078 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14079 ok( ret, "no message\n" );
14080 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14081 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14082 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14083 ok( !ret, "got message %x\n", msg.message );
14084
14085 /* sent message */
14086 flush_sequence();
14087 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14088 ok_sequence( WmEmptySeq, "no messages", FALSE );
14089 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14090 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14091 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14092 ok( !ret, "got message %x\n", msg.message );
14093
14094 /* sent message with timeout */
14095 flush_sequence();
14096 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14097 ok_sequence( WmEmptySeq, "no messages", FALSE );
14098 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14099 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14100 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14101 ok( !ret, "got message %x\n", msg.message );
14102
14103 /* sent message with timeout and callback */
14104 flush_sequence();
14105 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14106 ok_sequence( WmEmptySeq, "no messages", FALSE );
14107 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14108 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14109 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14110 ok( !ret, "got message %x\n", msg.message );
14111
14112 /* sent message with callback */
14113 flush_sequence();
14114 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14115 ok_sequence( WmEmptySeq, "no messages", FALSE );
14116 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14117 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14118 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14119 ok( !ret, "got message %x\n", msg.message );
14120
14121 /* direct window proc call */
14122 flush_sequence();
14123 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14124 ok_sequence( WmEmptySeq, "no messages", FALSE );
14125 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14126 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14127
14128 /* dispatch message */
14129 msg.hwnd = hwnd;
14130 msg.message = WM_CHAR;
14131 msg.wParam = dbch[0];
14132 msg.lParam = 0;
14133 DispatchMessageA( &msg );
14134 ok_sequence( WmEmptySeq, "no messages", FALSE );
14135 msg.wParam = dbch[1];
14136 DispatchMessageA( &msg );
14137 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14138
14139 /* window handle is irrelevant */
14140 flush_sequence();
14141 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14142 ok_sequence( WmEmptySeq, "no messages", FALSE );
14143 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14144 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14145 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14146 ok( !ret, "got message %x\n", msg.message );
14147
14148 /* interleaved post and send */
14149 flush_sequence();
14150 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14151 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14152 ok_sequence( WmEmptySeq, "no messages", FALSE );
14153 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14154 ok( !ret, "got message %x\n", msg.message );
14155 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14156 ok_sequence( WmEmptySeq, "no messages", FALSE );
14157 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14158 ok( ret, "no message\n" );
14159 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14160 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14161 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14162 ok( !ret, "got message %x\n", msg.message );
14163 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14164 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14165 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14166 ok( !ret, "got message %x\n", msg.message );
14167
14168 /* interleaved sent message and winproc */
14169 flush_sequence();
14170 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14171 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14172 ok_sequence( WmEmptySeq, "no messages", FALSE );
14173 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14174 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14175 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14176 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14177
14178 /* interleaved winproc and dispatch */
14179 msg.hwnd = hwnd;
14180 msg.message = WM_CHAR;
14181 msg.wParam = dbch[0];
14182 msg.lParam = 0;
14183 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14184 DispatchMessageA( &msg );
14185 ok_sequence( WmEmptySeq, "no messages", FALSE );
14186 msg.wParam = dbch[1];
14187 DispatchMessageA( &msg );
14188 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14189 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14190 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14191
14192 /* interleaved sends */
14193 flush_sequence();
14194 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14195 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14196 ok_sequence( WmEmptySeq, "no messages", FALSE );
14197 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14198 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14199 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14200 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14201
14202 /* dbcs WM_CHAR */
14203 flush_sequence();
14204 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14205 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14206 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14207 ok( !ret, "got message %x\n", msg.message );
14208
14209 /* other char messages are not magic */
14210 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14211 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14212 ok( ret, "no message\n" );
14213 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14214 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14215 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14216 ok( !ret, "got message %x\n", msg.message );
14217 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14218 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14219 ok( ret, "no message\n" );
14220 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14221 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14222 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14223 ok( !ret, "got message %x\n", msg.message );
14224
14225 /* test retrieving messages */
14226
14227 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14228 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14229 ok( ret, "no message\n" );
14230 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14231 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14232 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14233 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14234 ok( ret, "no message\n" );
14235 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14236 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14237 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14238 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14239 ok( !ret, "got message %x\n", msg.message );
14240
14241 /* message filters */
14242 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14243 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14244 ok( ret, "no message\n" );
14245 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14246 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14247 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14248 /* message id is filtered, hwnd is not */
14249 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14250 ok( !ret, "no message\n" );
14251 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14252 ok( ret, "no message\n" );
14253 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14254 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14255 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14256 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14257 ok( !ret, "got message %x\n", msg.message );
14258
14259 /* mixing GetMessage and PostMessage */
14260 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14261 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14262 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14263 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14264 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14265 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14266 time = msg.time;
14267 pt = msg.pt;
14268 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14269 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14270 ok( ret, "no message\n" );
14271 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14272 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14273 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14274 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14275 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14276 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 );
14277 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14278 ok( !ret, "got message %x\n", msg.message );
14279
14280 /* without PM_REMOVE */
14281 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14282 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14283 ok( ret, "no message\n" );
14284 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14285 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14286 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14287 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14288 ok( ret, "no message\n" );
14289 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14290 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14291 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14292 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14293 ok( ret, "no message\n" );
14294 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14295 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14296 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14297 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14298 ok( ret, "no message\n" );
14299 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14300 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14301 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14302 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14303 ok( !ret, "got message %x\n", msg.message );
14304
14305 DestroyWindow(hwnd);
14306 DestroyWindow(hwnd2);
14307 }
14308
14309 static void test_unicode_wm_char(void)
14310 {
14311 HWND hwnd;
14312 MSG msg;
14313 struct message seq[2];
14314 HKL hkl_orig, hkl_greek;
14315 DWORD cp;
14316 LCID thread_locale;
14317
14318 hkl_orig = GetKeyboardLayout( 0 );
14319 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14320 if (cp != 1252)
14321 {
14322 skip( "Default codepage %d\n", cp );
14323 return;
14324 }
14325
14326 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14327 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14328 {
14329 skip( "Unable to load Greek keyboard layout\n" );
14330 return;
14331 }
14332
14333 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14334 100, 100, 200, 200, 0, 0, 0, NULL );
14335 flush_sequence();
14336
14337 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14338
14339 while (GetMessageW( &msg, hwnd, 0, 0 ))
14340 {
14341 if (!ignore_message( msg.message )) break;
14342 }
14343
14344 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14345 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14346 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14347 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14348
14349 DispatchMessageW( &msg );
14350
14351 memset( seq, 0, sizeof(seq) );
14352 seq[0].message = WM_CHAR;
14353 seq[0].flags = sent|wparam;
14354 seq[0].wParam = 0x3b1;
14355
14356 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14357
14358 flush_sequence();
14359
14360 /* greek alpha -> 'a' in cp1252 */
14361 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14362
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 == 0x61, "bad wparam %lx\n", msg.wParam );
14367 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14368
14369 DispatchMessageA( &msg );
14370
14371 seq[0].wParam = 0x61;
14372 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14373
14374 thread_locale = GetThreadLocale();
14375 ActivateKeyboardLayout( hkl_greek, 0 );
14376 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14377 thread_locale, GetThreadLocale() );
14378
14379 flush_sequence();
14380
14381 /* greek alpha -> 0xe1 in cp1253 */
14382 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14383
14384 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14385 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14386 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14387 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14388 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14389
14390 DispatchMessageA( &msg );
14391
14392 seq[0].wParam = 0x3b1;
14393 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14394
14395 DestroyWindow( hwnd );
14396 ActivateKeyboardLayout( hkl_orig, 0 );
14397 UnloadKeyboardLayout( hkl_greek );
14398 }
14399
14400 #define ID_LISTBOX 0x000f
14401
14402 static const struct message wm_lb_setcursel_0[] =
14403 {
14404 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14405 { WM_CTLCOLORLISTBOX, sent|parent },
14406 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14407 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14408 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14409 { 0 }
14410 };
14411 static const struct message wm_lb_setcursel_1[] =
14412 {
14413 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14414 { WM_CTLCOLORLISTBOX, sent|parent },
14415 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14416 { WM_CTLCOLORLISTBOX, sent|parent },
14417 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14418 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14419 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14420 { 0 }
14421 };
14422 static const struct message wm_lb_setcursel_2[] =
14423 {
14424 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14425 { WM_CTLCOLORLISTBOX, sent|parent },
14426 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14427 { WM_CTLCOLORLISTBOX, sent|parent },
14428 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14429 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14430 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14431 { 0 }
14432 };
14433 static const struct message wm_lb_click_0[] =
14434 {
14435 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
14436 { HCBT_SETFOCUS, hook },
14437 { WM_KILLFOCUS, sent|parent },
14438 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
14439 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14440 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14441 { WM_SETFOCUS, sent|defwinproc },
14442
14443 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
14444 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
14445 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14446 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
14447 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14448
14449 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
14450 { WM_CTLCOLORLISTBOX, sent|parent },
14451 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
14452 { WM_CTLCOLORLISTBOX, sent|parent },
14453 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14454 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
14455
14456 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14457 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14458
14459 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
14460 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14461 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
14462 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
14463 { 0 }
14464 };
14465 static const struct message wm_lb_deletestring[] =
14466 {
14467 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14468 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14469 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14470 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14471 { 0 }
14472 };
14473 static const struct message wm_lb_deletestring_reset[] =
14474 {
14475 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14476 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
14477 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14478 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14479 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14480 { 0 }
14481 };
14482 static const struct message wm_lb_addstring[] =
14483 {
14484 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14485 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14486 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14487 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14488 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14489 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14490 { 0 }
14491 };
14492 static const struct message wm_lb_addstring_sort[] =
14493 {
14494 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14495 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14496 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14497 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
14498 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14499 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14500 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
14501 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
14502 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14503 { 0 }
14504 };
14505
14506 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
14507
14508 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
14509
14510 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14511 {
14512 static LONG defwndproc_counter = 0;
14513 LRESULT ret;
14514 struct recvd_message msg;
14515
14516 /* do not log painting messages */
14517 if (message != WM_PAINT &&
14518 message != WM_NCPAINT &&
14519 message != WM_SYNCPAINT &&
14520 message != WM_ERASEBKGND &&
14521 message != WM_NCHITTEST &&
14522 message != WM_GETTEXT &&
14523 !ignore_message( message ))
14524 {
14525 msg.hwnd = hwnd;
14526 msg.message = message;
14527 msg.flags = sent|wparam|lparam;
14528 if (defwndproc_counter) msg.flags |= defwinproc;
14529 msg.wParam = wp;
14530 if (message == LB_ADDSTRING)
14531 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
14532 else
14533 msg.lParam = lp;
14534 msg.descr = "listbox";
14535 add_message(&msg);
14536 }
14537
14538 defwndproc_counter++;
14539 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
14540 defwndproc_counter--;
14541
14542 return ret;
14543 }
14544
14545 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
14546 int caret_index, int top_index, int line)
14547 {
14548 LRESULT ret;
14549
14550 /* calling an orig proc helps to avoid unnecessary message logging */
14551 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14552 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14553 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14554 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14555 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14556 ok_(__FILE__, line)(ret == caret_index ||
14557 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
14558 "expected caret index %d, got %ld\n", caret_index, ret);
14559 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14560 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14561 }
14562
14563 static void test_listbox_messages(void)
14564 {
14565 HWND parent, listbox;
14566 LRESULT ret;
14567
14568 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14569 100, 100, 200, 200, 0, 0, 0, NULL);
14570 /* with LBS_HASSTRINGS */
14571 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14572 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14573 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14574 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14575
14576 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14577
14578 flush_sequence();
14579
14580 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14581 ok(ret == 0, "expected 0, got %ld\n", ret);
14582 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14583 ok(ret == 1, "expected 1, got %ld\n", ret);
14584 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14585 ok(ret == 2, "expected 2, got %ld\n", ret);
14586
14587 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
14588 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14589
14590 flush_sequence();
14591
14592 log_all_parent_messages++;
14593
14594 trace("selecting item 0\n");
14595 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14596 ok(ret == 0, "expected 0, got %ld\n", ret);
14597 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14598 check_lb_state(listbox, 3, 0, 0, 0);
14599 flush_sequence();
14600
14601 trace("selecting item 1\n");
14602 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14603 ok(ret == 1, "expected 1, got %ld\n", ret);
14604 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14605 check_lb_state(listbox, 3, 1, 1, 0);
14606
14607 trace("selecting item 2\n");
14608 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14609 ok(ret == 2, "expected 2, got %ld\n", ret);
14610 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14611 check_lb_state(listbox, 3, 2, 2, 0);
14612
14613 trace("clicking on item 0\n");
14614 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14615 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14616 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14617 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14618 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14619 check_lb_state(listbox, 3, 0, 0, 0);
14620 flush_sequence();
14621
14622 trace("deleting item 0\n");
14623 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14624 ok(ret == 2, "expected 2, got %ld\n", ret);
14625 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14626 check_lb_state(listbox, 2, -1, 0, 0);
14627 flush_sequence();
14628
14629 trace("deleting item 0\n");
14630 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14631 ok(ret == 1, "expected 1, got %ld\n", ret);
14632 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14633 check_lb_state(listbox, 1, -1, 0, 0);
14634 flush_sequence();
14635
14636 trace("deleting item 0\n");
14637 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14638 ok(ret == 0, "expected 0, got %ld\n", ret);
14639 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14640 check_lb_state(listbox, 0, -1, 0, 0);
14641 flush_sequence();
14642
14643 trace("deleting item 0\n");
14644 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14645 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14646 check_lb_state(listbox, 0, -1, 0, 0);
14647 flush_sequence();
14648
14649 log_all_parent_messages--;
14650
14651 DestroyWindow(listbox);
14652
14653 /* with LBS_SORT and without LBS_HASSTRINGS */
14654 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14655 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
14656 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14657 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14658
14659 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14660
14661 flush_sequence();
14662
14663 log_all_parent_messages++;
14664
14665 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14666 ok(ret == 0, "expected 0, got %ld\n", ret);
14667 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14668 ok(ret == 1, "expected 1, got %ld\n", ret);
14669 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14670 ok(ret == 2, "expected 2, got %ld\n", ret);
14671
14672 ok_sequence(wm_lb_addstring_sort, "LB_ADDSTRING", FALSE);
14673 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14674
14675 log_all_parent_messages--;
14676
14677 DestroyWindow(listbox);
14678 DestroyWindow(parent);
14679 }
14680
14681 /*************************** Menu test ******************************/
14682 static const struct message wm_popup_menu_1[] =
14683 {
14684 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14685 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14686 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
14687 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
14688 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
14689 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
14690 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14691 { WM_INITMENU, sent|lparam, 0, 0 },
14692 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
14693 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
14694 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
14695 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
14696 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
14697 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14698 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
14699 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
14700 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14701 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14702 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14703 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
14704 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14705 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14706 { 0 }
14707 };
14708 static const struct message wm_popup_menu_2[] =
14709 {
14710 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14711 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14712 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14713 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14714 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14715 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14716 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14717 { WM_INITMENU, sent|lparam, 0, 0 },
14718 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14719 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14720 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14721 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14722 { HCBT_CREATEWND, hook },
14723 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14724 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14725 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14726 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14727 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14728 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14729 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14730 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14731 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14732 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14733 { HCBT_DESTROYWND, hook },
14734 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14735 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14736 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14737 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14738 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14739 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
14740 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14741 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14742 { 0 }
14743 };
14744 static const struct message wm_popup_menu_3[] =
14745 {
14746 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14747 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14748 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14749 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14750 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14751 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14752 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14753 { WM_INITMENU, sent|lparam, 0, 0 },
14754 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14755 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14756 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14757 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14758 { HCBT_CREATEWND, hook },
14759 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14760 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14761 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14762 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14763 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14764 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14765 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14766 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14767 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14768 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14769 { HCBT_DESTROYWND, hook },
14770 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14771 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14772 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14773 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14774 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14775 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
14776 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14777 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14778 { 0 }
14779 };
14780
14781 static const struct message wm_single_menu_item[] =
14782 {
14783 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14784 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14785 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
14786 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
14787 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
14788 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
14789 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14790 { WM_INITMENU, sent|lparam, 0, 0 },
14791 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
14792 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14793 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14794 { WM_MENUCOMMAND, sent },
14795 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
14796 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
14797 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
14798 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
14799
14800 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
14801 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
14802 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
14803 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
14804 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
14805 { 0 }
14806 };
14807
14808 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14809 {
14810 if (message == WM_ENTERIDLE ||
14811 message == WM_INITMENU ||
14812 message == WM_INITMENUPOPUP ||
14813 message == WM_MENUSELECT ||
14814 message == WM_PARENTNOTIFY ||
14815 message == WM_ENTERMENULOOP ||
14816 message == WM_EXITMENULOOP ||
14817 message == WM_UNINITMENUPOPUP ||
14818 message == WM_KEYDOWN ||
14819 message == WM_KEYUP ||
14820 message == WM_CHAR ||
14821 message == WM_SYSKEYDOWN ||
14822 message == WM_SYSKEYUP ||
14823 message == WM_SYSCHAR ||
14824 message == WM_COMMAND ||
14825 message == WM_MENUCOMMAND)
14826 {
14827 struct recvd_message msg;
14828
14829 msg.hwnd = hwnd;
14830 msg.message = message;
14831 msg.flags = sent|wparam|lparam;
14832 msg.wParam = wp;
14833 msg.lParam = lp;
14834 msg.descr = "parent_menu_proc";
14835 add_message(&msg);
14836 }
14837
14838 return DefWindowProcA(hwnd, message, wp, lp);
14839 }
14840
14841 static void set_menu_style(HMENU hmenu, DWORD style)
14842 {
14843 MENUINFO mi;
14844 BOOL ret;
14845
14846 mi.cbSize = sizeof(mi);
14847 mi.fMask = MIM_STYLE;
14848 mi.dwStyle = style;
14849 SetLastError(0xdeadbeef);
14850 ret = pSetMenuInfo(hmenu, &mi);
14851 ok(ret, "SetMenuInfo error %u\n", GetLastError());
14852 }
14853
14854 static DWORD get_menu_style(HMENU hmenu)
14855 {
14856 MENUINFO mi;
14857 BOOL ret;
14858
14859 mi.cbSize = sizeof(mi);
14860 mi.fMask = MIM_STYLE;
14861 mi.dwStyle = 0;
14862 SetLastError(0xdeadbeef);
14863 ret = pGetMenuInfo(hmenu, &mi);
14864 ok(ret, "GetMenuInfo error %u\n", GetLastError());
14865
14866 return mi.dwStyle;
14867 }
14868
14869 static void test_menu_messages(void)
14870 {
14871 MSG msg;
14872 WNDCLASSA cls;
14873 HMENU hmenu, hmenu_popup;
14874 HWND hwnd;
14875 DWORD style;
14876
14877 if (!pGetMenuInfo || !pSetMenuInfo)
14878 {
14879 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
14880 return;
14881 }
14882 cls.style = 0;
14883 cls.lpfnWndProc = parent_menu_proc;
14884 cls.cbClsExtra = 0;
14885 cls.cbWndExtra = 0;
14886 cls.hInstance = GetModuleHandleA(0);
14887 cls.hIcon = 0;
14888 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
14889 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
14890 cls.lpszMenuName = NULL;
14891 cls.lpszClassName = "TestMenuClass";
14892 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14893 if (!RegisterClassA(&cls)) assert(0);
14894
14895 SetLastError(0xdeadbeef);
14896 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14897 100, 100, 200, 200, 0, 0, 0, NULL);
14898 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
14899
14900 SetLastError(0xdeadbeef);
14901 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
14902 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
14903
14904 SetMenu(hwnd, hmenu);
14905 SetForegroundWindow( hwnd );
14906 flush_events();
14907
14908 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
14909 style = get_menu_style(hmenu);
14910 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14911
14912 hmenu_popup = GetSubMenu(hmenu, 0);
14913 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14914 style = get_menu_style(hmenu_popup);
14915 ok(style == 0, "expected 0, got %u\n", style);
14916
14917 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14918 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14919 style = get_menu_style(hmenu_popup);
14920 ok(style == 0, "expected 0, got %u\n", style);
14921
14922 /* Alt+E, Enter */
14923 trace("testing a popup menu command\n");
14924 flush_sequence();
14925 keybd_event(VK_MENU, 0, 0, 0);
14926 keybd_event('E', 0, 0, 0);
14927 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
14928 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14929 keybd_event(VK_RETURN, 0, 0, 0);
14930 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14931 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14932 {
14933 TranslateMessage(&msg);
14934 DispatchMessageA(&msg);
14935 }
14936 if (!sequence_cnt) /* we didn't get any message */
14937 {
14938 skip( "queuing key events not supported\n" );
14939 goto done;
14940 }
14941 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
14942 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
14943 {
14944 win_skip( "menu tracking through VK_MENU not supported\n" );
14945 goto done;
14946 }
14947 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
14948
14949 /* Alt+F, Right, Enter */
14950 trace("testing submenu of a popup menu command\n");
14951 flush_sequence();
14952 keybd_event(VK_MENU, 0, 0, 0);
14953 keybd_event('F', 0, 0, 0);
14954 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
14955 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14956 keybd_event(VK_RIGHT, 0, 0, 0);
14957 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
14958 keybd_event(VK_RETURN, 0, 0, 0);
14959 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14960 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14961 {
14962 TranslateMessage(&msg);
14963 DispatchMessageA(&msg);
14964 }
14965 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
14966
14967 trace("testing single menu item command\n");
14968 flush_sequence();
14969 keybd_event(VK_MENU, 0, 0, 0);
14970 keybd_event('Q', 0, 0, 0);
14971 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
14972 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14973 keybd_event(VK_ESCAPE, 0, 0, 0);
14974 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
14975 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14976 {
14977 TranslateMessage(&msg);
14978 DispatchMessageA(&msg);
14979 }
14980 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
14981
14982 set_menu_style(hmenu, 0);
14983 style = get_menu_style(hmenu);
14984 ok(style == 0, "expected 0, got %u\n", style);
14985
14986 hmenu_popup = GetSubMenu(hmenu, 0);
14987 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14988 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
14989 style = get_menu_style(hmenu_popup);
14990 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14991
14992 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14993 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14994 style = get_menu_style(hmenu_popup);
14995 ok(style == 0, "expected 0, got %u\n", style);
14996
14997 /* Alt+F, Right, Enter */
14998 trace("testing submenu of a popup menu command\n");
14999 flush_sequence();
15000 keybd_event(VK_MENU, 0, 0, 0);
15001 keybd_event('F', 0, 0, 0);
15002 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15003 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15004 keybd_event(VK_RIGHT, 0, 0, 0);
15005 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15006 keybd_event(VK_RETURN, 0, 0, 0);
15007 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15008 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15009 {
15010 TranslateMessage(&msg);
15011 DispatchMessageA(&msg);
15012 }
15013 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15014
15015 done:
15016 DestroyWindow(hwnd);
15017 DestroyMenu(hmenu);
15018 }
15019
15020
15021 static void test_paintingloop(void)
15022 {
15023 HWND hwnd;
15024
15025 paint_loop_done = FALSE;
15026 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15027 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15028 100, 100, 100, 100, 0, 0, 0, NULL );
15029 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15030 ShowWindow(hwnd,SW_NORMAL);
15031 SetFocus(hwnd);
15032
15033 while (!paint_loop_done)
15034 {
15035 MSG msg;
15036 if (PeekMessageA(&msg, 0, 0, 0, 1))
15037 {
15038 TranslateMessage(&msg);
15039 DispatchMessageA(&msg);
15040 }
15041 }
15042 DestroyWindow(hwnd);
15043 }
15044
15045 static const struct message NCRBUTTONDOWNSeq[] =
15046 {
15047 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15048 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15049 { WM_CAPTURECHANGED, sent },
15050 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15051 { 0 }
15052 };
15053
15054 static const struct message NCXBUTTONUPSeq1[] =
15055 {
15056 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15057 { 0 }
15058 };
15059
15060 static const struct message NCXBUTTONUPSeq2[] =
15061 {
15062 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15063 { 0 }
15064 };
15065
15066 struct rbuttonup_thread_data
15067 {
15068 HWND hwnd;
15069 HANDLE wndproc_finished;
15070 };
15071
15072 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15073 {
15074 struct rbuttonup_thread_data *data = arg;
15075 DWORD ret;
15076
15077 ret = WaitForSingleObject( data->wndproc_finished, 500 );
15078 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15079 if( ret == WAIT_OBJECT_0 ) return 0;
15080
15081 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15082 return 0;
15083 }
15084
15085 static void test_defwinproc(void)
15086 {
15087 HWND hwnd;
15088 MSG msg;
15089 BOOL gotwmquit = FALSE;
15090 POINT pos;
15091 RECT rect;
15092 INT x, y;
15093 LRESULT res;
15094 struct rbuttonup_thread_data data;
15095 char buffA[64];
15096 HANDLE thread;
15097
15098 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15099 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15100 assert(hwnd);
15101 flush_events();
15102
15103 buffA[0] = 0;
15104 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15105 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15106
15107 /* Zero high word of the lParam */
15108 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15109 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15110
15111 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15112 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15113
15114 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15115 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15116
15117 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15118 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15119
15120 GetCursorPos(&pos);
15121 GetWindowRect(hwnd, &rect);
15122 x = (rect.left+rect.right) / 2;
15123 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15124 SetCursorPos(x, y);
15125 flush_events();
15126 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15127 ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15128
15129 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15130 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15131 flush_events();
15132
15133 flush_sequence();
15134 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15135 /* workaround for missing support for clicking on window frame */
15136 data.hwnd = hwnd;
15137 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15138 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15139
15140 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15141 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15142
15143 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15144 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15145 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15146
15147 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15148 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15149 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15150
15151 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15152 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15153 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15154
15155 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15156 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15157 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15158
15159 SetEvent( data.wndproc_finished );
15160 WaitForSingleObject( thread, 1000 );
15161 CloseHandle( data.wndproc_finished );
15162 CloseHandle( thread );
15163
15164 SetCursorPos(pos.x, pos.y);
15165
15166 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15167 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15168 if( msg.message == WM_QUIT) gotwmquit = TRUE;
15169 DispatchMessageA( &msg );
15170 }
15171 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15172 DestroyWindow( hwnd);
15173 }
15174
15175 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
15176 static void clear_clipboard_(int line, HWND hWnd)
15177 {
15178 BOOL succ;
15179 succ = OpenClipboard(hWnd);
15180 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15181 succ = EmptyClipboard();
15182 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15183 succ = CloseClipboard();
15184 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15185 }
15186
15187 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
15188 static void expect_HWND_(int line, HWND expected, HWND got)
15189 {
15190 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
15191 }
15192
15193 static WNDPROC pOldViewerProc;
15194
15195 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
15196 {
15197 static BOOL recursion_guard;
15198
15199 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
15200 {
15201 recursion_guard = TRUE;
15202 clear_clipboard(hWnd);
15203 recursion_guard = FALSE;
15204 }
15205 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
15206 }
15207
15208 static void test_clipboard_viewers(void)
15209 {
15210 static struct message wm_change_cb_chain[] =
15211 {
15212 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
15213 { 0 }
15214 };
15215 static const struct message wm_clipboard_destroyed[] =
15216 {
15217 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15218 { 0 }
15219 };
15220 static struct message wm_clipboard_changed[] =
15221 {
15222 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15223 { 0 }
15224 };
15225 static struct message wm_clipboard_changed_and_owned[] =
15226 {
15227 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15228 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15229 { 0 }
15230 };
15231
15232 HINSTANCE hInst = GetModuleHandleA(NULL);
15233 HWND hWnd1, hWnd2, hWnd3;
15234 HWND hOrigViewer;
15235 HWND hRet;
15236
15237 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
15238 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15239 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15240 GetDesktopWindow(), NULL, hInst, NULL);
15241 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
15242 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15243 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15244 GetDesktopWindow(), NULL, hInst, NULL);
15245 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
15246 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15247 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15248 GetDesktopWindow(), NULL, hInst, NULL);
15249 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
15250 assert(hWnd1 && hWnd2 && hWnd3);
15251
15252 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
15253 flush_sequence();
15254
15255 /* Test getting the clipboard viewer and setting the viewer to NULL. */
15256 hOrigViewer = GetClipboardViewer();
15257 hRet = SetClipboardViewer(NULL);
15258 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
15259 expect_HWND(hOrigViewer, hRet);
15260 expect_HWND(NULL, GetClipboardViewer());
15261
15262 /* Test registering hWnd1 as a viewer. */
15263 hRet = SetClipboardViewer(hWnd1);
15264 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15265 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
15266 expect_HWND(NULL, hRet);
15267 expect_HWND(hWnd1, GetClipboardViewer());
15268
15269 /* Test that changing the clipboard actually refreshes the registered viewer. */
15270 clear_clipboard(hWnd1);
15271 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15272 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
15273
15274 /* Again, but with different owner. */
15275 clear_clipboard(hWnd2);
15276 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
15277 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
15278
15279 /* Test re-registering same window. */
15280 hRet = SetClipboardViewer(hWnd1);
15281 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15282 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
15283 expect_HWND(hWnd1, hRet);
15284 expect_HWND(hWnd1, GetClipboardViewer());
15285
15286 /* Test ChangeClipboardChain. */
15287 ChangeClipboardChain(hWnd2, hWnd3);
15288 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15289 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
15290 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
15291 expect_HWND(hWnd1, GetClipboardViewer());
15292
15293 ChangeClipboardChain(hWnd2, NULL);
15294 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15295 wm_change_cb_chain[0].lParam = 0;
15296 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
15297 expect_HWND(hWnd1, GetClipboardViewer());
15298
15299 ChangeClipboardChain(NULL, hWnd2);
15300 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
15301 expect_HWND(hWnd1, GetClipboardViewer());
15302
15303 /* Actually change clipboard viewer with ChangeClipboardChain. */
15304 ChangeClipboardChain(hWnd1, hWnd2);
15305 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
15306 expect_HWND(hWnd2, GetClipboardViewer());
15307
15308 /* Test that no refresh messages are sent when viewer has unregistered. */
15309 clear_clipboard(hWnd2);
15310 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
15311
15312 /* Register hWnd1 again. */
15313 ChangeClipboardChain(hWnd2, hWnd1);
15314 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
15315 expect_HWND(hWnd1, GetClipboardViewer());
15316
15317 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
15318 * changes the clipboard. When this happens, the system shouldn't send
15319 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
15320 */
15321 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
15322 clear_clipboard(hWnd2);
15323 /* The clipboard owner is changed in recursive_viewer_proc: */
15324 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
15325 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
15326
15327 /* Test unregistering. */
15328 ChangeClipboardChain(hWnd1, NULL);
15329 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
15330 expect_HWND(NULL, GetClipboardViewer());
15331
15332 clear_clipboard(hWnd1);
15333 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
15334
15335 DestroyWindow(hWnd1);
15336 DestroyWindow(hWnd2);
15337 DestroyWindow(hWnd3);
15338 SetClipboardViewer(hOrigViewer);
15339 }
15340
15341 static void test_PostMessage(void)
15342 {
15343 static const struct
15344 {
15345 HWND hwnd;
15346 BOOL ret;
15347 } data[] =
15348 {
15349 { HWND_TOP /* 0 */, TRUE },
15350 { HWND_BROADCAST, TRUE },
15351 { HWND_BOTTOM, TRUE },
15352 { HWND_TOPMOST, TRUE },
15353 { HWND_NOTOPMOST, FALSE },
15354 { HWND_MESSAGE, FALSE },
15355 { (HWND)0xdeadbeef, FALSE }
15356 };
15357 int i;
15358 HWND hwnd;
15359 BOOL ret;
15360 MSG msg;
15361 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
15362
15363 SetLastError(0xdeadbeef);
15364 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
15365 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
15366 {
15367 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
15368 return;
15369 }
15370 assert(hwnd);
15371
15372 flush_events();
15373
15374 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
15375 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
15376
15377 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
15378 {
15379 memset(&msg, 0xab, sizeof(msg));
15380 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
15381 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
15382 if (data[i].ret)
15383 {
15384 if (data[i].hwnd)
15385 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
15386 msg.wParam == 0x5678 && msg.lParam == 0x1234,
15387 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
15388 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
15389 else
15390 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
15391 msg.wParam == 0x1234 && msg.lParam == 0x5678,
15392 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
15393 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
15394 }
15395 }
15396
15397 DestroyWindow(hwnd);
15398 flush_events();
15399 }
15400
15401 static LPARAM g_broadcast_lparam;
15402 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15403 {
15404 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
15405
15406 if (wParam == 0xbaadbeef)
15407 g_broadcast_lparam = wParam;
15408 else
15409 g_broadcast_lparam = 0;
15410
15411 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
15412 }
15413
15414 static void test_broadcast(void)
15415 {
15416 static const UINT messages[] =
15417 {
15418 WM_USER-1,
15419 WM_USER,
15420 WM_USER+1,
15421 0xc000-1,
15422 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
15423 0xffff,
15424 };
15425 WNDPROC oldproc;
15426 unsigned int i;
15427 HWND hwnd;
15428
15429 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
15430 ok(hwnd != NULL, "got %p\n", hwnd);
15431
15432 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
15433 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
15434
15435 for (i = 0; i < sizeof(messages)/sizeof(messages[0]); i++)
15436 {
15437 BOOL ret;
15438 MSG msg;
15439
15440 flush_events();
15441 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15442 ;
15443
15444 /* post, broadcast */
15445 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
15446 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15447
15448 memset(&msg, 0xab, sizeof(msg));
15449 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15450 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15451 {
15452 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15453 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15454 }
15455 else
15456 {
15457 ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15458 }
15459
15460 /* post, topmost */
15461 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
15462 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15463
15464 memset(&msg, 0xab, sizeof(msg));
15465 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15466 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15467 {
15468 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15469 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15470 }
15471 else
15472 {
15473 ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15474 }
15475
15476 /* send, broadcast */
15477 g_broadcast_lparam = 0xdead;
15478 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15479 if (!ret && GetLastError() == ERROR_TIMEOUT)
15480 win_skip("broadcasting test %d, timeout\n", i);
15481 else
15482 {
15483 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15484 {
15485 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15486 g_broadcast_lparam, GetLastError());
15487 }
15488 else
15489 {
15490 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15491 g_broadcast_lparam, GetLastError());
15492 }
15493 }
15494
15495 /* send, topmost */
15496 g_broadcast_lparam = 0xdead;
15497 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15498 if (!ret && GetLastError() == ERROR_TIMEOUT)
15499 win_skip("broadcasting test %d, timeout\n", i);
15500 else
15501 {
15502 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15503 {
15504 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15505 g_broadcast_lparam, GetLastError());
15506 }
15507 else
15508 {
15509 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15510 g_broadcast_lparam, GetLastError());
15511 }
15512 }
15513 }
15514
15515 DestroyWindow(hwnd);
15516 }
15517
15518 static const struct
15519 {
15520 DWORD exp, broken;
15521 BOOL todo;
15522 } wait_idle_expect[] =
15523 {
15524 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15525 { WAIT_TIMEOUT, 0, FALSE },
15526 { WAIT_TIMEOUT, 0, FALSE },
15527 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15528 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15529 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
15530 { WAIT_TIMEOUT, 0, FALSE },
15531 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15532 { 0, 0, FALSE },
15533 { 0, 0, FALSE },
15534 /* 10 */ { 0, 0, FALSE },
15535 { 0, 0, FALSE },
15536 { 0, WAIT_TIMEOUT, FALSE },
15537 { 0, 0, FALSE },
15538 { 0, 0, FALSE },
15539 /* 15 */ { 0, 0, FALSE },
15540 { WAIT_TIMEOUT, 0, FALSE },
15541 { WAIT_TIMEOUT, 0, FALSE },
15542 { WAIT_TIMEOUT, 0, FALSE },
15543 { WAIT_TIMEOUT, 0, FALSE },
15544 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
15545 };
15546
15547 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
15548 {
15549 MSG msg;
15550
15551 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15552 Sleep( 200 );
15553 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15554 return 0;
15555 }
15556
15557 static void do_wait_idle_child( int arg )
15558 {
15559 WNDCLASSA cls;
15560 MSG msg;
15561 HWND hwnd = 0;
15562 HANDLE thread;
15563 DWORD id;
15564 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
15565 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
15566
15567 memset( &cls, 0, sizeof(cls) );
15568 cls.lpfnWndProc = DefWindowProcA;
15569 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15570 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15571 cls.lpszClassName = "TestClass";
15572 RegisterClassA( &cls );
15573
15574 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
15575
15576 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
15577 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
15578
15579 switch (arg)
15580 {
15581 case 0:
15582 SetEvent( start_event );
15583 break;
15584 case 1:
15585 SetEvent( start_event );
15586 Sleep( 200 );
15587 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15588 break;
15589 case 2:
15590 SetEvent( start_event );
15591 Sleep( 200 );
15592 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15593 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
15594 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15595 break;
15596 case 3:
15597 SetEvent( start_event );
15598 Sleep( 200 );
15599 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
15600 break;
15601 case 4:
15602 SetEvent( start_event );
15603 Sleep( 200 );
15604 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15605 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15606 break;
15607 case 5:
15608 SetEvent( start_event );
15609 Sleep( 200 );
15610 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15611 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15612 break;
15613 case 6:
15614 SetEvent( start_event );
15615 Sleep( 200 );
15616 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15617 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
15618 {
15619 GetMessageA( &msg, 0, 0, 0 );
15620 DispatchMessageA( &msg );
15621 }
15622 break;
15623 case 7:
15624 SetEvent( start_event );
15625 Sleep( 200 );
15626 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15627 SetTimer( hwnd, 3, 1, NULL );
15628 Sleep( 200 );
15629 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15630 break;
15631 case 8:
15632 SetEvent( start_event );
15633 Sleep( 200 );
15634 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15635 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15636 break;
15637 case 9:
15638 SetEvent( start_event );
15639 Sleep( 200 );
15640 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15641 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15642 for (;;) GetMessageA( &msg, 0, 0, 0 );
15643 break;
15644 case 10:
15645 SetEvent( start_event );
15646 Sleep( 200 );
15647 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15648 SetTimer( hwnd, 3, 1, NULL );
15649 Sleep( 200 );
15650 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15651 break;
15652 case 11:
15653 SetEvent( start_event );
15654 Sleep( 200 );
15655 return; /* exiting the process makes WaitForInputIdle return success too */
15656 case 12:
15657 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15658 Sleep( 200 );
15659 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15660 SetEvent( start_event );
15661 break;
15662 case 13:
15663 SetEvent( start_event );
15664 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15665 Sleep( 200 );
15666 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
15667 WaitForSingleObject( thread, 10000 );
15668 CloseHandle( thread );
15669 break;
15670 case 14:
15671 SetEvent( start_event );
15672 Sleep( 200 );
15673 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
15674 break;
15675 case 15:
15676 SetEvent( start_event );
15677 Sleep( 200 );
15678 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
15679 break;
15680 case 16:
15681 SetEvent( start_event );
15682 Sleep( 200 );
15683 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
15684 break;
15685 case 17:
15686 SetEvent( start_event );
15687 Sleep( 200 );
15688 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
15689 break;
15690 case 18:
15691 SetEvent( start_event );
15692 Sleep( 200 );
15693 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
15694 break;
15695 case 19:
15696 SetEvent( start_event );
15697 Sleep( 200 );
15698 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
15699 break;
15700 case 20:
15701 SetEvent( start_event );
15702 Sleep( 200 );
15703 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
15704 break;
15705 }
15706 WaitForSingleObject( end_event, 2000 );
15707 CloseHandle( start_event );
15708 CloseHandle( end_event );
15709 if (hwnd) DestroyWindow( hwnd );
15710 }
15711
15712 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
15713 {
15714 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
15715 return DefWindowProcA( hwnd, msg, wp, lp );
15716 }
15717
15718 static DWORD CALLBACK wait_idle_thread( void *arg )
15719 {
15720 WNDCLASSA cls;
15721 MSG msg;
15722 HWND hwnd;
15723
15724 memset( &cls, 0, sizeof(cls) );
15725 cls.lpfnWndProc = wait_idle_proc;
15726 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15727 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15728 cls.lpszClassName = "TestClass";
15729 RegisterClassA( &cls );
15730
15731 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
15732 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
15733 DestroyWindow(hwnd);
15734 return 0;
15735 }
15736
15737 static void test_WaitForInputIdle( char *argv0 )
15738 {
15739 char path[MAX_PATH];
15740 PROCESS_INFORMATION pi;
15741 STARTUPINFOA startup;
15742 BOOL ret;
15743 HANDLE start_event, end_event, thread;
15744 unsigned int i;
15745 DWORD id;
15746 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
15747 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
15748 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
15749
15750 if (console_app) /* build the test with -mwindows for better coverage */
15751 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
15752
15753 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
15754 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
15755 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
15756 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
15757
15758 memset( &startup, 0, sizeof(startup) );
15759 startup.cb = sizeof(startup);
15760 startup.dwFlags = STARTF_USESHOWWINDOW;
15761 startup.wShowWindow = SW_SHOWNORMAL;
15762
15763 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
15764
15765 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
15766 {
15767 ResetEvent( start_event );
15768 ResetEvent( end_event );
15769 #ifndef __REACTOS__
15770 sprintf( path, "%s msg %u", argv0, i );
15771 #else
15772 sprintf( path, "%s msg_queue %u", argv0, i );
15773 #endif
15774 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
15775 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
15776 if (ret)
15777 {
15778 ret = WaitForSingleObject( start_event, 5000 );
15779 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
15780 if (ret == WAIT_OBJECT_0)
15781 {
15782 ret = WaitForInputIdle( pi.hProcess, 1000 );
15783 if (ret == WAIT_FAILED)
15784 ok( console_app ||
15785 ret == wait_idle_expect[i].exp ||
15786 broken(ret == wait_idle_expect[i].broken),
15787 "%u: WaitForInputIdle error %08x expected %08x\n",
15788 i, ret, wait_idle_expect[i].exp );
15789 else todo_wine_if (wait_idle_expect[i].todo)
15790 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
15791 "%u: WaitForInputIdle error %08x expected %08x\n",
15792 i, ret, wait_idle_expect[i].exp );
15793 SetEvent( end_event );
15794 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
15795 }
15796 TerminateProcess( pi.hProcess, 0 ); /* just in case */
15797 winetest_wait_child_process( pi.hProcess );
15798 ret = WaitForInputIdle( pi.hProcess, 100 );
15799 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
15800 CloseHandle( pi.hProcess );
15801 CloseHandle( pi.hThread );
15802 }
15803 }
15804 CloseHandle( start_event );
15805 PostThreadMessageA( id, WM_QUIT, 0, 0 );
15806 WaitForSingleObject( thread, 10000 );
15807 CloseHandle( thread );
15808 }
15809
15810 static const struct message WmSetParentSeq_1[] = {
15811 { WM_SHOWWINDOW, sent|wparam, 0 },
15812 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15813 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15814 { WM_CHILDACTIVATE, sent },
15815 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
15816 { WM_MOVE, sent|defwinproc|wparam, 0 },
15817 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15818 { WM_SHOWWINDOW, sent|wparam, 1 },
15819 { 0 }
15820 };
15821
15822 static const struct message WmSetParentSeq_2[] = {
15823 { WM_SHOWWINDOW, sent|wparam, 0 },
15824 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15825 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15826 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15827 { HCBT_SETFOCUS, hook|optional },
15828 { WM_NCACTIVATE, sent|wparam|optional, 0 },
15829 { WM_ACTIVATE, sent|wparam|optional, 0 },
15830 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15831 { WM_KILLFOCUS, sent|wparam, 0 },
15832 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15833 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15834 { HCBT_ACTIVATE, hook|optional },
15835 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
15836 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15837 { WM_NCACTIVATE, sent|wparam|optional, 1 },
15838 { WM_ACTIVATE, sent|wparam|optional, 1 },
15839 { HCBT_SETFOCUS, hook|optional },
15840 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15841 { WM_SETFOCUS, sent|optional|defwinproc },
15842 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
15843 { WM_MOVE, sent|defwinproc|wparam, 0 },
15844 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15845 { WM_SHOWWINDOW, sent|wparam, 1 },
15846 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15847 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15848 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15849 { 0 }
15850 };
15851
15852
15853 static void test_SetParent(void)
15854 {
15855 HWND parent1, parent2, child, popup;
15856 RECT rc, rc_old;
15857
15858 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15859 100, 100, 200, 200, 0, 0, 0, NULL);
15860 ok(parent1 != 0, "Failed to create parent1 window\n");
15861
15862 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15863 400, 100, 200, 200, 0, 0, 0, NULL);
15864 ok(parent2 != 0, "Failed to create parent2 window\n");
15865
15866 /* WS_CHILD window */
15867 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
15868 10, 10, 150, 150, parent1, 0, 0, NULL);
15869 ok(child != 0, "Failed to create child window\n");
15870
15871 GetWindowRect(parent1, &rc);
15872 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
15873 GetWindowRect(child, &rc_old);
15874 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
15875 trace("child %s\n", wine_dbgstr_rect(&rc_old));
15876
15877 flush_sequence();
15878
15879 SetParent(child, parent2);
15880 flush_events();
15881 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
15882
15883 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15884 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
15885
15886 GetWindowRect(parent2, &rc);
15887 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15888 GetWindowRect(child, &rc);
15889 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
15890 trace("child %s\n", wine_dbgstr_rect(&rc));
15891
15892 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15893 wine_dbgstr_rect(&rc));
15894
15895 /* WS_POPUP window */
15896 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
15897 20, 20, 100, 100, 0, 0, 0, NULL);
15898 ok(popup != 0, "Failed to create popup window\n");
15899
15900 GetWindowRect(popup, &rc_old);
15901 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
15902
15903 flush_sequence();
15904
15905 SetParent(popup, child);
15906 flush_events();
15907 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
15908
15909 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15910 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
15911
15912 GetWindowRect(child, &rc);
15913 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15914 GetWindowRect(popup, &rc);
15915 MapWindowPoints(0, child, (POINT *)&rc, 2);
15916 trace("popup %s\n", wine_dbgstr_rect(&rc));
15917
15918 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15919 wine_dbgstr_rect(&rc));
15920
15921 DestroyWindow(popup);
15922 DestroyWindow(child);
15923 DestroyWindow(parent1);
15924 DestroyWindow(parent2);
15925
15926 flush_sequence();
15927 }
15928
15929 static const struct message WmKeyReleaseOnly[] = {
15930 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
15931 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
15932 { 0 }
15933 };
15934 static const struct message WmKeyPressNormal[] = {
15935 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
15936 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
15937 { 0 }
15938 };
15939 static const struct message WmKeyPressRepeat[] = {
15940 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
15941 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
15942 { 0 }
15943 };
15944 static const struct message WmKeyReleaseNormal[] = {
15945 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
15946 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
15947 { 0 }
15948 };
15949
15950 static void test_keyflags(void)
15951 {
15952 HWND test_window;
15953 SHORT key_state;
15954 BYTE keyboard_state[256];
15955 MSG msg;
15956
15957 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15958 100, 100, 200, 200, 0, 0, 0, NULL);
15959
15960 flush_events();
15961 flush_sequence();
15962
15963 /* keyup without a keydown */
15964 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15965 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15966 DispatchMessageA(&msg);
15967 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
15968
15969 key_state = GetAsyncKeyState(0x41);
15970 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15971
15972 key_state = GetKeyState(0x41);
15973 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15974
15975 /* keydown */
15976 keybd_event(0x41, 0, 0, 0);
15977 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15978 DispatchMessageA(&msg);
15979 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
15980
15981 key_state = GetAsyncKeyState(0x41);
15982 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15983
15984 key_state = GetKeyState(0x41);
15985 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15986
15987 /* keydown repeat */
15988 keybd_event(0x41, 0, 0, 0);
15989 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15990 DispatchMessageA(&msg);
15991 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
15992
15993 key_state = GetAsyncKeyState(0x41);
15994 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15995
15996 key_state = GetKeyState(0x41);
15997 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15998
15999 /* keyup */
16000 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16001 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16002 DispatchMessageA(&msg);
16003 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
16004
16005 key_state = GetAsyncKeyState(0x41);
16006 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16007
16008 key_state = GetKeyState(0x41);
16009 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16010
16011 /* set the key state in this thread */
16012 GetKeyboardState(keyboard_state);
16013 keyboard_state[0x41] = 0x80;
16014 SetKeyboardState(keyboard_state);
16015
16016 key_state = GetAsyncKeyState(0x41);
16017 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16018
16019 /* keydown */
16020 keybd_event(0x41, 0, 0, 0);
16021 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16022 DispatchMessageA(&msg);
16023 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16024
16025 key_state = GetAsyncKeyState(0x41);
16026 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16027
16028 key_state = GetKeyState(0x41);
16029 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16030
16031 /* clear the key state in this thread */
16032 GetKeyboardState(keyboard_state);
16033 keyboard_state[0x41] = 0;
16034 SetKeyboardState(keyboard_state);
16035
16036 key_state = GetAsyncKeyState(0x41);
16037 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16038
16039 /* keyup */
16040 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16041 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16042 DispatchMessageA(&msg);
16043 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16044
16045 key_state = GetAsyncKeyState(0x41);
16046 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16047
16048 key_state = GetKeyState(0x41);
16049 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16050
16051 DestroyWindow(test_window);
16052 flush_sequence();
16053 }
16054
16055 static const struct message WmHotkeyPressLWIN[] = {
16056 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16057 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16058 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16059 { 0 }
16060 };
16061 static const struct message WmHotkeyPress[] = {
16062 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16063 { WM_HOTKEY, sent|wparam, 5 },
16064 { 0 }
16065 };
16066 static const struct message WmHotkeyRelease[] = {
16067 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16068 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16069 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16070 { 0 }
16071 };
16072 static const struct message WmHotkeyReleaseLWIN[] = {
16073 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16074 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16075 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16076 { 0 }
16077 };
16078 static const struct message WmHotkeyCombined[] = {
16079 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16080 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16081 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16082 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16083 { WM_APP, sent, 0, 0 },
16084 { WM_HOTKEY, sent|wparam, 5 },
16085 { WM_APP+1, sent, 0, 0 },
16086 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16087 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16088 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16089 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16090 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16091 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16092 { 0 }
16093 };
16094 static const struct message WmHotkeyPrevious[] = {
16095 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16096 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16097 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16098 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16099 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16100 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16101 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16102 { WM_KEYDOWN, sent|lparam, 0, 1 },
16103 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16104 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16105 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16106 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16107 { 0 }
16108 };
16109 static const struct message WmHotkeyNew[] = {
16110 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16111 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16112 { WM_HOTKEY, sent|wparam, 5 },
16113 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16114 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16115 { 0 }
16116 };
16117
16118 static int hotkey_letter;
16119
16120 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16121 {
16122 struct recvd_message msg;
16123
16124 if (nCode == HC_ACTION)
16125 {
16126 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16127
16128 msg.hwnd = 0;
16129 msg.message = wParam;
16130 msg.flags = kbd_hook|wparam|lparam;
16131 msg.wParam = kdbhookstruct->vkCode;
16132 msg.lParam = kdbhookstruct->flags;
16133 msg.descr = "KeyboardHookProc";
16134 add_message(&msg);
16135
16136 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16137 {
16138 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
16139 "unexpected keycode %x\n", kdbhookstruct->vkCode);
16140 }
16141 }
16142
16143 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
16144 }
16145
16146 static void test_hotkey(void)
16147 {
16148 HWND test_window, taskbar_window;
16149 BOOL ret;
16150 MSG msg;
16151 DWORD queue_status;
16152 SHORT key_state;
16153
16154 SetLastError(0xdeadbeef);
16155 ret = UnregisterHotKey(NULL, 0);
16156 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16157 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16158 "unexpected error %d\n", GetLastError());
16159
16160 if (ret == TRUE)
16161 {
16162 skip("hotkeys not supported\n");
16163 return;
16164 }
16165
16166 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16167 100, 100, 200, 200, 0, 0, 0, NULL);
16168
16169 flush_sequence();
16170
16171 SetLastError(0xdeadbeef);
16172 ret = UnregisterHotKey(test_window, 0);
16173 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16174 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16175 "unexpected error %d\n", GetLastError());
16176
16177 /* Search for a Windows Key + letter combination that hasn't been registered */
16178 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
16179 {
16180 SetLastError(0xdeadbeef);
16181 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16182
16183 if (ret == TRUE)
16184 {
16185 break;
16186 }
16187 else
16188 {
16189 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16190 "unexpected error %d\n", GetLastError());
16191 }
16192 }
16193
16194 if (hotkey_letter == 0x52)
16195 {
16196 ok(0, "Couldn't find any free Windows Key + letter combination\n");
16197 goto end;
16198 }
16199
16200 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
16201 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
16202
16203 /* Same key combination, different id */
16204 SetLastError(0xdeadbeef);
16205 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
16206 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16207 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16208 "unexpected error %d\n", GetLastError());
16209
16210 /* Same key combination, different window */
16211 SetLastError(0xdeadbeef);
16212 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16213 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16214 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16215 "unexpected error %d\n", GetLastError());
16216
16217 /* Register the same hotkey twice */
16218 SetLastError(0xdeadbeef);
16219 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16220 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16221 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16222 "unexpected error %d\n", GetLastError());
16223
16224 /* Window on another thread */
16225 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
16226 if (!taskbar_window)
16227 {
16228 skip("no taskbar?\n");
16229 }
16230 else
16231 {
16232 SetLastError(0xdeadbeef);
16233 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
16234 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16235 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
16236 "unexpected error %d\n", GetLastError());
16237 }
16238
16239 /* Inject the appropriate key sequence */
16240 keybd_event(VK_LWIN, 0, 0, 0);
16241 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16242 DispatchMessageA(&msg);
16243 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
16244
16245 keybd_event(hotkey_letter, 0, 0, 0);
16246 queue_status = GetQueueStatus(QS_HOTKEY);
16247 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16248 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16249 {
16250 if (msg.message == WM_HOTKEY)
16251 {
16252 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16253 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16254 }
16255 DispatchMessageA(&msg);
16256 }
16257 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
16258
16259 queue_status = GetQueueStatus(QS_HOTKEY);
16260 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
16261
16262 key_state = GetAsyncKeyState(hotkey_letter);
16263 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16264
16265 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16266 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16267 DispatchMessageA(&msg);
16268 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
16269
16270 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16271 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16272 DispatchMessageA(&msg);
16273 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
16274
16275 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
16276 PostMessageA(test_window, WM_HOTKEY, 0, 0);
16277 queue_status = GetQueueStatus(QS_HOTKEY);
16278 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16279 queue_status = GetQueueStatus(QS_POSTMESSAGE);
16280 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
16281 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16282 DispatchMessageA(&msg);
16283 flush_sequence();
16284
16285 /* Send and process all messages at once */
16286 PostMessageA(test_window, WM_APP, 0, 0);
16287 keybd_event(VK_LWIN, 0, 0, 0);
16288 keybd_event(hotkey_letter, 0, 0, 0);
16289 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16290 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16291
16292 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16293 {
16294 if (msg.message == WM_HOTKEY)
16295 {
16296 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16297 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16298 }
16299 DispatchMessageA(&msg);
16300 }
16301 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
16302
16303 /* Register same hwnd/id with different key combination */
16304 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
16305 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16306
16307 /* Previous key combination does not work */
16308 keybd_event(VK_LWIN, 0, 0, 0);
16309 keybd_event(hotkey_letter, 0, 0, 0);
16310 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16311 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16312
16313 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16314 DispatchMessageA(&msg);
16315 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
16316
16317 /* New key combination works */
16318 keybd_event(hotkey_letter, 0, 0, 0);
16319 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16320
16321 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16322 {
16323 if (msg.message == WM_HOTKEY)
16324 {
16325 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16326 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16327 }
16328 DispatchMessageA(&msg);
16329 }
16330 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
16331
16332 /* Unregister hotkey properly */
16333 ret = UnregisterHotKey(test_window, 5);
16334 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16335
16336 /* Unregister hotkey again */
16337 SetLastError(0xdeadbeef);
16338 ret = UnregisterHotKey(test_window, 5);
16339 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16340 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16341 "unexpected error %d\n", GetLastError());
16342
16343 /* Register thread hotkey */
16344 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16345 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16346
16347 /* Inject the appropriate key sequence */
16348 keybd_event(VK_LWIN, 0, 0, 0);
16349 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16350 {
16351 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16352 DispatchMessageA(&msg);
16353 }
16354 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
16355
16356 keybd_event(hotkey_letter, 0, 0, 0);
16357 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16358 {
16359 if (msg.message == WM_HOTKEY)
16360 {
16361 struct recvd_message message;
16362 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
16363 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16364 message.message = msg.message;
16365 message.flags = sent|wparam|lparam;
16366 message.wParam = msg.wParam;
16367 message.lParam = msg.lParam;
16368 message.descr = "test_hotkey thread message";
16369 add_message(&message);
16370 }
16371 else
16372 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16373 DispatchMessageA(&msg);
16374 }
16375 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
16376
16377 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16378 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16379 {
16380 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16381 DispatchMessageA(&msg);
16382 }
16383 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
16384
16385 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16386 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16387 {
16388 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16389 DispatchMessageA(&msg);
16390 }
16391 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
16392
16393 /* Unregister thread hotkey */
16394 ret = UnregisterHotKey(NULL, 5);
16395 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16396
16397 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
16398 hKBD_hook = NULL;
16399
16400 end:
16401 UnregisterHotKey(NULL, 5);
16402 UnregisterHotKey(test_window, 5);
16403 DestroyWindow(test_window);
16404 flush_sequence();
16405 }
16406
16407
16408 static const struct message WmSetFocus_1[] = {
16409 { HCBT_SETFOCUS, hook }, /* child */
16410 { HCBT_ACTIVATE, hook }, /* parent */
16411 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
16412 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
16413 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
16414 { WM_NCACTIVATE, sent|parent },
16415 { WM_GETTEXT, sent|defwinproc|parent|optional },
16416 { WM_GETTEXT, sent|defwinproc|parent|optional },
16417 { WM_ACTIVATE, sent|wparam|parent, 1 },
16418 { HCBT_SETFOCUS, hook }, /* parent */
16419 { WM_SETFOCUS, sent|defwinproc|parent },
16420 { WM_KILLFOCUS, sent|parent },
16421 { WM_SETFOCUS, sent },
16422 { 0 }
16423 };
16424 static const struct message WmSetFocus_2[] = {
16425 { HCBT_SETFOCUS, hook }, /* parent */
16426 { WM_KILLFOCUS, sent },
16427 { WM_SETFOCUS, sent|parent },
16428 { 0 }
16429 };
16430 static const struct message WmSetFocus_3[] = {
16431 { HCBT_SETFOCUS, hook }, /* child */
16432 { 0 }
16433 };
16434
16435 static void test_SetFocus(void)
16436 {
16437 HWND parent, old_parent, child, old_focus, old_active;
16438 MSG msg;
16439 struct wnd_event wnd_event;
16440 HANDLE hthread;
16441 DWORD ret, tid;
16442
16443 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
16444 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
16445 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
16446 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
16447 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
16448 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16449 CloseHandle(wnd_event.start_event);
16450
16451 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16452 0, 0, 0, 0, 0, 0, 0, NULL);
16453 ok(parent != 0, "failed to create parent window\n");
16454 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
16455 0, 0, 0, 0, parent, 0, 0, NULL);
16456 ok(child != 0, "failed to create child window\n");
16457
16458 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
16459
16460 SetFocus(0);
16461 SetActiveWindow(0);
16462
16463 flush_events();
16464 flush_sequence();
16465
16466 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16467 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16468
16469 log_all_parent_messages++;
16470
16471 old_focus = SetFocus(child);
16472 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16473 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
16474 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16475 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16476 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
16477
16478 old_focus = SetFocus(parent);
16479 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16480 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
16481 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
16482 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16483 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16484
16485 SetLastError(0xdeadbeef);
16486 old_focus = SetFocus((HWND)0xdeadbeef);
16487 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16488 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16489 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16490 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
16491 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16492 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16493 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16494
16495 SetLastError(0xdeadbeef);
16496 old_focus = SetFocus(GetDesktopWindow());
16497 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16498 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16499 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16500 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
16501 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16502 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16503 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16504
16505 SetLastError(0xdeadbeef);
16506 old_focus = SetFocus(wnd_event.hwnd);
16507 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16508 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16509 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16510 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
16511 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16512 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16513 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16514
16515 SetLastError(0xdeadbeef);
16516 old_active = SetActiveWindow((HWND)0xdeadbeef);
16517 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16518 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16519 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16520 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
16521 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16522 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16523 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16524
16525 SetLastError(0xdeadbeef);
16526 old_active = SetActiveWindow(GetDesktopWindow());
16527 todo_wine
16528 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16529 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16530 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
16531 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
16532 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16533 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16534
16535 SetLastError(0xdeadbeef);
16536 old_active = SetActiveWindow(wnd_event.hwnd);
16537 todo_wine
16538 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16539 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16540 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
16541 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16542 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16543 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16544
16545 SetLastError(0xdeadbeef);
16546 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
16547 ok(ret, "AttachThreadInput error %d\n", GetLastError());
16548
16549 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16550 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16551
16552 flush_events();
16553 flush_sequence();
16554
16555 old_focus = SetFocus(wnd_event.hwnd);
16556 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16557 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
16558 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16559 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16560
16561 old_focus = SetFocus(parent);
16562 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16563 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16564 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16565 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16566
16567 flush_events();
16568 flush_sequence();
16569
16570 old_active = SetActiveWindow(wnd_event.hwnd);
16571 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16572 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
16573 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16574 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16575
16576 SetLastError(0xdeadbeef);
16577 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
16578 ok(ret, "AttachThreadInput error %d\n", GetLastError());
16579
16580 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16581 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16582
16583 old_parent = SetParent(child, GetDesktopWindow());
16584 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
16585
16586 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16587 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16588
16589 old_focus = SetFocus(parent);
16590 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16591 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16592 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16593 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16594
16595 flush_events();
16596 flush_sequence();
16597
16598 SetLastError(0xdeadbeef);
16599 old_focus = SetFocus(child);
16600 todo_wine
16601 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
16602 broken(GetLastError() == 0) /* XP */ ||
16603 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
16604 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16605 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
16606 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16607 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16608 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16609
16610 SetLastError(0xdeadbeef);
16611 old_active = SetActiveWindow(child);
16612 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16613 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16614 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
16615 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
16616 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16617 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16618
16619 log_all_parent_messages--;
16620
16621 DestroyWindow(child);
16622 DestroyWindow(parent);
16623
16624 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
16625 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
16626 ret = WaitForSingleObject(hthread, INFINITE);
16627 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16628 CloseHandle(hthread);
16629 }
16630
16631 static const struct message WmSetLayeredStyle[] = {
16632 { WM_STYLECHANGING, sent },
16633 { WM_STYLECHANGED, sent },
16634 { WM_GETTEXT, sent|defwinproc|optional },
16635 { 0 }
16636 };
16637
16638 static const struct message WmSetLayeredStyle2[] = {
16639 { WM_STYLECHANGING, sent },
16640 { WM_STYLECHANGED, sent },
16641 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16642 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
16643 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16644 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
16645 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
16646 { 0 }
16647 };
16648
16649 struct layered_window_info
16650 {
16651 HWND hwnd;
16652 HDC hdc;
16653 SIZE size;
16654 HANDLE event;
16655 BOOL ret;
16656 };
16657
16658 static DWORD CALLBACK update_layered_proc( void *param )
16659 {
16660 struct layered_window_info *info = param;
16661 POINT src = { 0, 0 };
16662
16663 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
16664 info->hdc, &src, 0, NULL, ULW_OPAQUE );
16665 ok( info->ret, "failed\n");
16666 SetEvent( info->event );
16667 return 0;
16668 }
16669
16670 static void test_layered_window(void)
16671 {
16672 HWND hwnd;
16673 HDC hdc;
16674 HBITMAP bmp;
16675 BOOL ret;
16676 SIZE size;
16677 POINT pos, src;
16678 RECT rect, client;
16679 HANDLE thread;
16680 DWORD tid;
16681 struct layered_window_info info;
16682
16683 if (!pUpdateLayeredWindow)
16684 {
16685 win_skip( "UpdateLayeredWindow not supported\n" );
16686 return;
16687 }
16688
16689 hdc = CreateCompatibleDC( 0 );
16690 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
16691 SelectObject( hdc, bmp );
16692
16693 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
16694 100, 100, 300, 300, 0, 0, 0, NULL);
16695 ok( hwnd != 0, "failed to create window\n" );
16696 ShowWindow( hwnd, SW_SHOWNORMAL );
16697 UpdateWindow( hwnd );
16698 flush_events();
16699 flush_sequence();
16700
16701 GetWindowRect( hwnd, &rect );
16702 GetClientRect( hwnd, &client );
16703 ok( client.right < rect.right - rect.left, "wrong client area\n" );
16704 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
16705
16706 src.x = src.y = 0;
16707 pos.x = pos.y = 300;
16708 size.cx = size.cy = 250;
16709 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16710 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16711 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16712 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16713 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16714
16715 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16716 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16717 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16718 GetWindowRect( hwnd, &rect );
16719 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
16720 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16721 GetClientRect( hwnd, &rect );
16722 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
16723 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16724
16725 size.cx = 150;
16726 pos.y = 200;
16727 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16728 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16729 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16730 GetWindowRect( hwnd, &rect );
16731 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
16732 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16733 GetClientRect( hwnd, &rect );
16734 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
16735 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16736
16737 SetWindowLongA( hwnd, GWL_STYLE,
16738 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
16739 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
16740
16741 size.cx = 200;
16742 pos.x = 200;
16743 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16744 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16745 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16746 GetWindowRect( hwnd, &rect );
16747 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16748 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16749 GetClientRect( hwnd, &rect );
16750 ok( (rect.right == 200 && rect.bottom == 250) ||
16751 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16752 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16753
16754 size.cx = 0;
16755 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16756 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16757 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
16758 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
16759 size.cx = 1;
16760 size.cy = -1;
16761 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16762 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16763 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16764
16765 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
16766 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16767 GetWindowRect( hwnd, &rect );
16768 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16769 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16770 GetClientRect( hwnd, &rect );
16771 ok( (rect.right == 200 && rect.bottom == 250) ||
16772 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16773 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16774
16775 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16776 info.hwnd = hwnd;
16777 info.hdc = hdc;
16778 info.size.cx = 250;
16779 info.size.cy = 300;
16780 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
16781 info.ret = FALSE;
16782 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
16783 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
16784 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
16785 WaitForSingleObject( thread, 1000 );
16786 CloseHandle( thread );
16787 GetWindowRect( hwnd, &rect );
16788 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
16789 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16790 GetClientRect( hwnd, &rect );
16791 ok( (rect.right == 250 && rect.bottom == 300) ||
16792 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
16793 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16794
16795 DestroyWindow( hwnd );
16796 DeleteDC( hdc );
16797 DeleteObject( bmp );
16798 }
16799
16800 static HMENU hpopupmenu;
16801
16802 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16803 {
16804 if (ignore_message( message )) return 0;
16805
16806 switch (message) {
16807 case WM_ENTERIDLE:
16808 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
16809 EndMenu();
16810 break;
16811 case WM_INITMENU:
16812 case WM_INITMENUPOPUP:
16813 case WM_UNINITMENUPOPUP:
16814 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
16815 break;
16816 case WM_CAPTURECHANGED:
16817 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
16818 break;
16819 }
16820
16821 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16822 }
16823
16824 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16825 {
16826 if (ignore_message( message )) return 0;
16827
16828 switch (message) {
16829 case WM_ENTERMENULOOP:
16830 ok(EndMenu() == TRUE, "EndMenu() failed\n");
16831 break;
16832 }
16833
16834 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16835 }
16836
16837 static void test_TrackPopupMenu(void)
16838 {
16839 MSG msg;
16840 HWND hwnd;
16841 BOOL ret;
16842
16843 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16844 0, 0, 1, 1, 0,
16845 NULL, NULL, 0);
16846 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16847
16848 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16849
16850 hpopupmenu = CreatePopupMenu();
16851 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16852
16853 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
16854 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
16855
16856 flush_events();
16857 flush_sequence();
16858 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16859 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
16860 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16861
16862 /* Test popup closing with an ESC-press */
16863 flush_events();
16864 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
16865 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16866 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16867 PostQuitMessage(0);
16868 flush_sequence();
16869 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
16870 {
16871 TranslateMessage(&msg);
16872 DispatchMessageA(&msg);
16873 }
16874 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
16875
16876 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
16877
16878 flush_events();
16879 flush_sequence();
16880 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16881 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
16882 ok(ret == TRUE, "TrackPopupMenu failed\n");
16883
16884 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16885
16886 SetCapture(hwnd);
16887
16888 flush_events();
16889 flush_sequence();
16890 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16891 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
16892 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
16893
16894 DestroyMenu(hpopupmenu);
16895 DestroyWindow(hwnd);
16896 }
16897
16898 static void test_TrackPopupMenuEmpty(void)
16899 {
16900 HWND hwnd;
16901 BOOL ret;
16902
16903 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16904 0, 0, 1, 1, 0,
16905 NULL, NULL, 0);
16906 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16907
16908 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16909
16910 hpopupmenu = CreatePopupMenu();
16911 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16912
16913 flush_events();
16914 flush_sequence();
16915 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16916 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
16917 ok(ret == 0, "TrackPopupMenu succeeded\n");
16918
16919 DestroyMenu(hpopupmenu);
16920 DestroyWindow(hwnd);
16921 }
16922
16923 static const struct message send_message_1[] = {
16924 { WM_USER+2, sent|wparam|lparam, 0, 0 },
16925 { WM_USER, sent|wparam|lparam, 0, 0 },
16926 { 0 }
16927 };
16928 static const struct message send_message_2[] = {
16929 { WM_USER+4, sent|wparam|lparam, 0, 0 },
16930 { 0 }
16931 };
16932 static const struct message send_message_3[] = {
16933 { WM_USER+3, sent|wparam|lparam, 0, 0 },
16934 { 0 }
16935 };
16936 static const struct message send_message_4[] = {
16937 { WM_USER+1, sent|wparam|lparam, 0, 0 },
16938 { 0 }
16939 };
16940
16941 static DWORD WINAPI SendMessage_thread_1(void *param)
16942 {
16943 struct wnd_event *wnd_event = param;
16944
16945 trace("thread: starting\n");
16946 WaitForSingleObject(wnd_event->start_event, INFINITE);
16947
16948 trace("thread: call PostMessage\n");
16949 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16950
16951 trace("thread: call PostMessage\n");
16952 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16953
16954 trace("thread: call SendMessage\n");
16955 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16956
16957 trace("thread: call SendMessage\n");
16958 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16959
16960 return 0;
16961 }
16962
16963 static DWORD WINAPI SendMessage_thread_2(void *param)
16964 {
16965 struct wnd_event *wnd_event = param;
16966
16967 trace("thread: starting\n");
16968 WaitForSingleObject(wnd_event->start_event, INFINITE);
16969
16970 trace("thread: call PostMessage\n");
16971 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16972
16973 trace("thread: call PostMessage\n");
16974 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16975
16976 /* this leads to sending an internal message under Wine */
16977 trace("thread: call SetParent\n");
16978 SetParent(wnd_event->hwnd, wnd_event->hwnd);
16979
16980 trace("thread: call SendMessage\n");
16981 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16982
16983 trace("thread: call SendMessage\n");
16984 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16985
16986 return 0;
16987 }
16988
16989 static void test_SendMessage_other_thread(int thread_n)
16990 {
16991 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
16992 HANDLE hthread;
16993 struct wnd_event wnd_event;
16994 DWORD tid, ret;
16995 MSG msg;
16996
16997 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
16998
16999 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
17000 100, 100, 200, 200, 0, 0, 0, NULL);
17001 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
17002
17003 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
17004 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
17005 CloseHandle(hthread);
17006
17007 flush_events();
17008 flush_sequence();
17009
17010 ret = GetQueueStatus(QS_SENDMESSAGE);
17011 ok(ret == 0, "wrong status %08x\n", ret);
17012
17013 SetEvent(wnd_event.start_event);
17014
17015 /* wait for other thread's SendMessage */
17016 for (;;)
17017 {
17018 ret = GetQueueStatus(QS_SENDMESSAGE);
17019 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17020 Sleep(50);
17021 }
17022
17023 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17024 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17025
17026 trace("main: call GetMessage\n");
17027 GetMessageA(&msg, 0, 0, 0);
17028 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17029 DispatchMessageA(&msg);
17030 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17031
17032 /* intentionally yield */
17033 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17034
17035 trace("main: call SendMessage\n");
17036 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17037 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17038
17039 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17040 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17041
17042 trace("main: call PeekMessage\n");
17043 ok(PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "PeekMessage should not fail\n");
17044 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17045 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17046
17047 trace("main: call PeekMessage\n");
17048 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17049 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17050 DispatchMessageA(&msg);
17051 ok_sequence(send_message_4, "SendMessage from other thread 4", FALSE);
17052
17053 /* intentionally yield */
17054 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17055
17056 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17057 /* FIXME: remove once Wine is fixed */
17058 todo_wine_if (thread_n == 2)
17059 ok(ret == 0, "wrong status %08x\n", ret);
17060
17061 trace("main: call PeekMessage\n");
17062 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17063 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17064
17065 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17066 ok(ret == 0, "wrong status %08x\n", ret);
17067
17068 trace("main: call DestroyWindow\n");
17069 DestroyWindow(msg.hwnd);
17070
17071 flush_events();
17072 flush_sequence();
17073 }
17074
17075 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17076 {
17077 DWORD flags = InSendMessageEx( NULL );
17078 BOOL ret;
17079
17080 switch (msg)
17081 {
17082 case WM_USER:
17083 ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17084 ok( InSendMessage(), "InSendMessage returned false\n" );
17085 ret = ReplyMessage( msg );
17086 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17087 flags = InSendMessageEx( NULL );
17088 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17089 ok( InSendMessage(), "InSendMessage returned false\n" );
17090 break;
17091 case WM_USER + 1:
17092 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17093 ok( InSendMessage(), "InSendMessage returned false\n" );
17094 ret = ReplyMessage( msg );
17095 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17096 flags = InSendMessageEx( NULL );
17097 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17098 ok( InSendMessage(), "InSendMessage returned false\n" );
17099 break;
17100 case WM_USER + 2:
17101 ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17102 ok( InSendMessage(), "InSendMessage returned false\n" );
17103 ret = ReplyMessage( msg );
17104 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17105 flags = InSendMessageEx( NULL );
17106 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
17107 ok( InSendMessage(), "InSendMessage returned false\n" );
17108 break;
17109 case WM_USER + 3:
17110 ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
17111 ok( !InSendMessage(), "InSendMessage returned true\n" );
17112 ret = ReplyMessage( msg );
17113 ok( !ret, "ReplyMessage succeeded\n" );
17114 break;
17115 }
17116
17117 return DefWindowProcA( hwnd, msg, wp, lp );
17118 }
17119
17120 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
17121 {
17122 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
17123 ok( result == WM_USER + 2, "wrong result %lx\n", result );
17124 }
17125
17126 static DWORD WINAPI send_message_thread( void *arg )
17127 {
17128 HWND win = arg;
17129
17130 SendMessageA( win, WM_USER, 0, 0 );
17131 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
17132 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
17133 PostMessageA( win, WM_USER + 3, 0, 0 );
17134 PostMessageA( win, WM_QUIT, 0, 0 );
17135 return 0;
17136 }
17137
17138 static void test_InSendMessage(void)
17139 {
17140 WNDCLASSA cls;
17141 HWND win;
17142 MSG msg;
17143 HANDLE thread;
17144 DWORD tid;
17145
17146 memset(&cls, 0, sizeof(cls));
17147 cls.lpfnWndProc = insendmessage_wnd_proc;
17148 cls.hInstance = GetModuleHandleA(NULL);
17149 cls.lpszClassName = "InSendMessage_test";
17150 RegisterClassA(&cls);
17151
17152 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
17153 ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
17154
17155 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
17156 ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
17157
17158 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
17159
17160 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
17161 CloseHandle( thread );
17162
17163 DestroyWindow( win );
17164 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
17165 }
17166
17167 static const struct message DoubleSetCaptureSeq[] =
17168 {
17169 { WM_CAPTURECHANGED, sent },
17170 { 0 }
17171 };
17172
17173 static void test_DoubleSetCapture(void)
17174 {
17175 HWND hwnd;
17176
17177 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
17178 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17179 100, 100, 200, 200, 0, 0, 0, NULL);
17180 ok (hwnd != 0, "Failed to create overlapped window\n");
17181
17182 ShowWindow( hwnd, SW_SHOW );
17183 UpdateWindow( hwnd );
17184 flush_events();
17185 flush_sequence();
17186
17187 SetCapture( hwnd );
17188 SetCapture( hwnd );
17189 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
17190
17191 DestroyWindow(hwnd);
17192 }
17193
17194 static void init_funcs(void)
17195 {
17196 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
17197
17198 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
17199 X(ActivateActCtx);
17200 X(CreateActCtxW);
17201 X(DeactivateActCtx);
17202 X(GetCurrentActCtx);
17203 X(QueryActCtxW);
17204 X(ReleaseActCtx);
17205 #undef X
17206 }
17207
17208 #ifndef __REACTOS__
17209 START_TEST(msg)
17210 {
17211 char **test_argv;
17212 BOOL ret;
17213 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17214 HMODULE hModuleImm32;
17215 BOOL (WINAPI *pImmDisableIME)(DWORD);
17216 int argc;
17217
17218 init_funcs();
17219
17220 argc = winetest_get_mainargs( &test_argv );
17221 if (argc >= 3)
17222 {
17223 unsigned int arg;
17224 /* Child process. */
17225 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17226 do_wait_idle_child( arg );
17227 return;
17228 }
17229
17230 InitializeCriticalSection( &sequence_cs );
17231 init_procs();
17232
17233 hModuleImm32 = LoadLibraryA("imm32.dll");
17234 if (hModuleImm32) {
17235 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17236 if (pImmDisableIME)
17237 pImmDisableIME(0);
17238 }
17239 pImmDisableIME = NULL;
17240 FreeLibrary(hModuleImm32);
17241
17242 if (!RegisterWindowClasses()) assert(0);
17243
17244 if (pSetWinEventHook)
17245 {
17246 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17247 GetModuleHandleA(0), win_event_proc,
17248 0, GetCurrentThreadId(),
17249 WINEVENT_INCONTEXT);
17250 if (pIsWinEventHookInstalled && hEvent_hook)
17251 {
17252 UINT event;
17253 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17254 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17255 }
17256 }
17257 if (!hEvent_hook) win_skip( "no win event hook support\n" );
17258
17259 cbt_hook_thread_id = GetCurrentThreadId();
17260 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17261 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17262
17263 test_winevents();
17264
17265 /* Fix message sequences before removing 4 lines below */
17266 if (pUnhookWinEvent && hEvent_hook)
17267 {
17268 ret = pUnhookWinEvent(hEvent_hook);
17269 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17270 pUnhookWinEvent = 0;
17271 }
17272 hEvent_hook = 0;
17273
17274 test_SendMessage_other_thread(1);
17275 test_SendMessage_other_thread(2);
17276 test_InSendMessage();
17277 test_SetFocus();
17278 test_SetParent();
17279 test_PostMessage();
17280 test_broadcast();
17281 test_ShowWindow();
17282 test_PeekMessage();
17283 test_PeekMessage2();
17284 test_PeekMessage3();
17285 test_WaitForInputIdle( test_argv[0] );
17286 test_scrollwindowex();
17287 test_messages();
17288 test_setwindowpos();
17289 test_showwindow();
17290 invisible_parent_tests();
17291 test_mdi_messages();
17292 test_button_messages();
17293 test_autoradio_BM_CLICK();
17294 test_autoradio_kbd_move();
17295 test_static_messages();
17296 test_listbox_messages();
17297 test_combobox_messages();
17298 test_wmime_keydown_message();
17299 test_paint_messages();
17300 test_interthread_messages();
17301 test_message_conversion();
17302 test_accelerators();
17303 test_timers();
17304 test_timers_no_wnd();
17305 test_timers_exceptions();
17306 if (hCBT_hook)
17307 {
17308 test_set_hook();
17309 test_recursive_hook();
17310 }
17311 test_DestroyWindow();
17312 test_DispatchMessage();
17313 test_SendMessageTimeout();
17314 test_edit_messages();
17315 test_quit_message();
17316 test_notify_message();
17317 test_SetActiveWindow();
17318
17319 if (!pTrackMouseEvent)
17320 win_skip("TrackMouseEvent is not available\n");
17321 else
17322 test_TrackMouseEvent();
17323
17324 test_SetWindowRgn();
17325 test_sys_menu();
17326 test_dialog_messages();
17327 test_EndDialog();
17328 test_nullCallback();
17329 test_dbcs_wm_char();
17330 test_unicode_wm_char();
17331 test_menu_messages();
17332 test_paintingloop();
17333 test_defwinproc();
17334 test_clipboard_viewers();
17335 test_keyflags();
17336 test_hotkey();
17337 test_layered_window();
17338 test_TrackPopupMenu();
17339 test_TrackPopupMenuEmpty();
17340 test_DoubleSetCapture();
17341 /* keep it the last test, under Windows it tends to break the tests
17342 * which rely on active/foreground windows being correct.
17343 */
17344 test_SetForegroundWindow();
17345
17346 UnhookWindowsHookEx(hCBT_hook);
17347 if (pUnhookWinEvent && hEvent_hook)
17348 {
17349 ret = pUnhookWinEvent(hEvent_hook);
17350 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17351 SetLastError(0xdeadbeef);
17352 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17353 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17354 GetLastError() == 0xdeadbeef, /* Win9x */
17355 "unexpected error %d\n", GetLastError());
17356 }
17357 DeleteCriticalSection( &sequence_cs );
17358 }
17359 #endif /* __REACTOS__ */
17360
17361 static void init_tests()
17362 {
17363 HMODULE hModuleImm32;
17364 BOOL (WINAPI *pImmDisableIME)(DWORD);
17365
17366 init_funcs();
17367
17368 InitializeCriticalSection( &sequence_cs );
17369 init_procs();
17370
17371 hModuleImm32 = LoadLibraryA("imm32.dll");
17372 if (hModuleImm32) {
17373 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17374 if (pImmDisableIME)
17375 pImmDisableIME(0);
17376 }
17377 pImmDisableIME = NULL;
17378 FreeLibrary(hModuleImm32);
17379
17380 if (!RegisterWindowClasses()) assert(0);
17381
17382 cbt_hook_thread_id = GetCurrentThreadId();
17383 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17384 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17385 }
17386
17387 static void cleanup_tests()
17388 {
17389 BOOL ret;
17390 UnhookWindowsHookEx(hCBT_hook);
17391 if (pUnhookWinEvent && hEvent_hook)
17392 {
17393 ret = pUnhookWinEvent(hEvent_hook);
17394 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17395 SetLastError(0xdeadbeef);
17396 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17397 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17398 GetLastError() == 0xdeadbeef, /* Win9x */
17399 "unexpected error %d\n", GetLastError());
17400 }
17401 DeleteCriticalSection( &sequence_cs );
17402
17403 }
17404
17405 START_TEST(msg_queue)
17406 {
17407 int argc;
17408 char **test_argv;
17409 argc = winetest_get_mainargs( &test_argv );
17410 if (argc >= 3)
17411 {
17412 unsigned int arg;
17413 /* Child process. */
17414 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17415 do_wait_idle_child( arg );
17416 return;
17417 }
17418
17419 init_tests();
17420 test_SendMessage_other_thread(1);
17421 test_SendMessage_other_thread(2);
17422 test_InSendMessage();
17423 test_PostMessage();
17424 test_broadcast();
17425 test_PeekMessage();
17426 test_PeekMessage2();
17427 test_PeekMessage3();
17428 test_interthread_messages();
17429 test_DispatchMessage();
17430 test_SendMessageTimeout();
17431 test_quit_message();
17432 test_notify_message();
17433 test_WaitForInputIdle( test_argv[0] );
17434 test_DestroyWindow();
17435 cleanup_tests();
17436 }
17437
17438 START_TEST(msg_messages)
17439 {
17440 init_tests();
17441 test_message_conversion();
17442 test_messages();
17443 test_wmime_keydown_message();
17444 test_nullCallback();
17445 test_dbcs_wm_char();
17446 test_unicode_wm_char();
17447 test_defwinproc();
17448 cleanup_tests();
17449 }
17450
17451 START_TEST(msg_focus)
17452 {
17453 init_tests();
17454
17455 test_SetFocus();
17456
17457 /* HACK: For some reason the tests fail on Windows if run consecutively.
17458 * Putting these in between helps, and is essentially what happens in the
17459 * "normal" msg test. */
17460 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17461 flush_events();
17462
17463 test_SetActiveWindow();
17464
17465 /* HACK */
17466 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17467 flush_events();
17468
17469 test_DoubleSetCapture();
17470
17471 /* keep it the last test, under Windows it tends to break the tests
17472 * which rely on active/foreground windows being correct.
17473 */
17474 test_SetForegroundWindow();
17475 cleanup_tests();
17476 }
17477
17478 START_TEST(msg_winpos)
17479 {
17480 init_tests();
17481 test_SetParent();
17482 test_ShowWindow();
17483 test_setwindowpos();
17484 test_showwindow();
17485 test_SetWindowRgn();
17486 invisible_parent_tests();
17487 cleanup_tests();
17488 }
17489
17490 START_TEST(msg_paint)
17491 {
17492 init_tests();
17493 test_scrollwindowex();
17494 test_paint_messages();
17495 #ifdef __REACTOS__
17496 if (!winetest_interactive &&
17497 !strcmp(winetest_platform, "windows"))
17498 {
17499 skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
17500 }
17501 else
17502 #endif
17503 test_paintingloop();
17504 cleanup_tests();
17505 }
17506
17507 START_TEST(msg_input)
17508 {
17509 init_tests();
17510 test_accelerators();
17511 if (!pTrackMouseEvent)
17512 win_skip("TrackMouseEvent is not available\n");
17513 else
17514 test_TrackMouseEvent();
17515
17516 test_keyflags();
17517 test_hotkey();
17518 cleanup_tests();
17519 }
17520
17521 START_TEST(msg_timer)
17522 {
17523 init_tests();
17524 test_timers();
17525 test_timers_no_wnd();
17526 test_timers_exceptions();
17527 cleanup_tests();
17528 }
17529
17530 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
17531
17532 START_TEST(msg_hook)
17533 {
17534 // HMODULE user32 = GetModuleHandleA("user32.dll");
17535 // IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
17536 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17537
17538 init_tests();
17539
17540 if (pSetWinEventHook)
17541 {
17542 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17543 GetModuleHandleA(0), win_event_proc,
17544 0, GetCurrentThreadId(),
17545 WINEVENT_INCONTEXT);
17546 if (pIsWinEventHookInstalled && hEvent_hook)
17547 {
17548 UINT event;
17549 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17550 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17551 }
17552 }
17553 if (!hEvent_hook) win_skip( "no win event hook support\n" );
17554
17555 test_winevents();
17556
17557 /* Fix message sequences before removing 4 lines below */
17558 if (pUnhookWinEvent && hEvent_hook)
17559 {
17560 BOOL ret;
17561 ret = pUnhookWinEvent(hEvent_hook);
17562 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17563 pUnhookWinEvent = 0;
17564 }
17565 hEvent_hook = 0;
17566 if (hCBT_hook)
17567 {
17568 test_set_hook();
17569 test_recursive_hook();
17570 }
17571 cleanup_tests();
17572 }
17573
17574 START_TEST(msg_menu)
17575 {
17576 init_tests();
17577 test_sys_menu();
17578 test_menu_messages();
17579 test_TrackPopupMenu();
17580 test_TrackPopupMenuEmpty();
17581 cleanup_tests();
17582 }
17583
17584 START_TEST(msg_mdi)
17585 {
17586 init_tests();
17587 test_mdi_messages();
17588 cleanup_tests();
17589 }
17590
17591 START_TEST(msg_controls)
17592 {
17593 init_tests();
17594 test_button_messages();
17595 test_autoradio_BM_CLICK();
17596 test_autoradio_kbd_move();
17597 test_static_messages();
17598 test_listbox_messages();
17599 test_combobox_messages();
17600 test_edit_messages();
17601 cleanup_tests();
17602 }
17603
17604 START_TEST(msg_layered_window)
17605 {
17606 init_tests();
17607 test_layered_window();
17608 cleanup_tests();
17609 }
17610
17611 START_TEST(msg_dialog)
17612 {
17613 init_tests();
17614 test_dialog_messages();
17615 test_EndDialog();
17616 cleanup_tests();
17617 }
17618
17619 START_TEST(msg_clipboard)
17620 {
17621 init_tests();
17622 test_clipboard_viewers();
17623 cleanup_tests();
17624 }