[ADVAPI32_WINETEST]
[reactos.git] / rostests / winetests / user32 / msg.c
1 /*
2 * Unit tests for window message handling
3 *
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004, 2005 Dmitry Timoshkov
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 //#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
36 #include "wine/test.h"
37
38 #define MDI_FIRST_CHILD_ID 2004
39
40 /* undocumented SWP flags - from SDK 3.1 */
41 #define SWP_NOCLIENTSIZE 0x0800
42 #define SWP_NOCLIENTMOVE 0x1000
43 #define SWP_STATECHANGED 0x8000
44
45 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
46
47 #ifndef WM_KEYF1
48 #define WM_KEYF1 0x004d
49 #endif
50
51 #ifndef WM_SYSTIMER
52 #define WM_SYSTIMER 0x0118
53 #endif
54
55 #define WND_PARENT_ID 1
56 #define WND_POPUP_ID 2
57 #define WND_CHILD_ID 3
58
59 #ifndef WM_LBTRACKPOINT
60 #define WM_LBTRACKPOINT 0x0131
61 #endif
62
63 #ifdef __i386__
64 #define ARCH "x86"
65 #elif defined __x86_64__
66 #define ARCH "amd64"
67 #else
68 #define ARCH "none"
69 #endif
70
71 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
72 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
73 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
74 static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
75 static void (WINAPI *pReleaseActCtx)(HANDLE);
76
77 /* encoded DRAWITEMSTRUCT into an LPARAM */
78 typedef struct
79 {
80 union
81 {
82 struct
83 {
84 UINT type : 4; /* ODT_* flags */
85 UINT ctl_id : 4; /* Control ID */
86 UINT item_id : 4; /* Menu item ID */
87 UINT action : 4; /* ODA_* flags */
88 UINT state : 16; /* ODS_* flags */
89 } item;
90 LPARAM lp;
91 } u;
92 } DRAW_ITEM_STRUCT;
93
94 static BOOL test_DestroyWindow_flag;
95 static HWINEVENTHOOK hEvent_hook;
96 static HHOOK hKBD_hook;
97 static HHOOK hCBT_hook;
98 static DWORD cbt_hook_thread_id;
99
100 static const WCHAR testWindowClassW[] =
101 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
102
103 /*
104 FIXME: add tests for these
105 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
106 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
107 WS_THICKFRAME: thick border
108 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
109 WS_BORDER (default for overlapped windows): single black border
110 none (default for child (and popup?) windows): no border
111 */
112
113 typedef enum {
114 sent=0x1,
115 posted=0x2,
116 parent=0x4,
117 wparam=0x8,
118 lparam=0x10,
119 defwinproc=0x20,
120 beginpaint=0x40,
121 optional=0x80,
122 hook=0x100,
123 winevent_hook=0x200,
124 kbd_hook=0x400
125 } msg_flags_t;
126
127 struct message {
128 UINT message; /* the WM_* code */
129 msg_flags_t flags; /* message props */
130 WPARAM wParam; /* expected value of wParam */
131 LPARAM lParam; /* expected value of lParam */
132 WPARAM wp_mask; /* mask for wParam checks */
133 LPARAM lp_mask; /* mask for lParam checks */
134 };
135
136 struct recvd_message {
137 UINT message; /* the WM_* code */
138 msg_flags_t flags; /* message props */
139 HWND hwnd; /* window that received the message */
140 WPARAM wParam; /* expected value of wParam */
141 LPARAM lParam; /* expected value of lParam */
142 int line; /* source line where logged */
143 const char *descr; /* description for trace output */
144 char output[512]; /* trace output */
145 };
146
147 /* Empty message sequence */
148 static const struct message WmEmptySeq[] =
149 {
150 { 0 }
151 };
152 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
153 static const struct message WmCreateOverlappedSeq[] = {
154 { HCBT_CREATEWND, hook },
155 { WM_GETMINMAXINFO, sent },
156 { WM_NCCREATE, sent },
157 { WM_NCCALCSIZE, sent|wparam, 0 },
158 { 0x0093, sent|defwinproc|optional },
159 { 0x0094, sent|defwinproc|optional },
160 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
161 { WM_CREATE, sent },
162 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
163 { 0 }
164 };
165 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
166 * for a not visible overlapped window.
167 */
168 static const struct message WmSWP_ShowOverlappedSeq[] = {
169 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
170 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
171 { WM_NCPAINT, sent|wparam|optional, 1 },
172 { WM_GETTEXT, sent|defwinproc|optional },
173 { WM_ERASEBKGND, sent|optional },
174 { HCBT_ACTIVATE, hook },
175 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
176 { WM_NOTIFYFORMAT, sent|optional },
177 { WM_QUERYUISTATE, sent|optional },
178 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
179 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
180 { WM_ACTIVATEAPP, sent|wparam, 1 },
181 { WM_NCACTIVATE, sent },
182 { WM_GETTEXT, sent|defwinproc|optional },
183 { WM_ACTIVATE, sent|wparam, 1 },
184 { HCBT_SETFOCUS, hook },
185 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
186 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
187 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
188 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
189 { WM_GETTEXT, sent|optional },
190 { WM_NCPAINT, sent|wparam|optional, 1 },
191 { WM_GETTEXT, sent|defwinproc|optional },
192 { WM_ERASEBKGND, sent|optional },
193 /* Win9x adds SWP_NOZORDER below */
194 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
195 { WM_GETTEXT, sent|optional },
196 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
197 { WM_NCPAINT, sent|wparam|optional, 1 },
198 { WM_ERASEBKGND, sent|optional },
199 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
200 { WM_SYNCPAINT, sent|optional },
201 { WM_GETTITLEBARINFOEX, sent|optional },
202 { WM_PAINT, sent|optional },
203 { WM_NCPAINT, sent|beginpaint|optional },
204 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
205 { WM_ERASEBKGND, sent|beginpaint|optional },
206 { 0 }
207 };
208 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
209 * for a visible overlapped window.
210 */
211 static const struct message WmSWP_HideOverlappedSeq[] = {
212 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
213 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
214 { HCBT_ACTIVATE, hook|optional },
215 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
216 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
217 { WM_NCACTIVATE, sent|optional },
218 { WM_ACTIVATE, sent|optional },
219 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
220 { 0 }
221 };
222
223 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
224 * for a visible overlapped window.
225 */
226 static const struct message WmSWP_ResizeSeq[] = {
227 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
228 { WM_GETMINMAXINFO, sent|defwinproc },
229 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
230 { WM_NCPAINT, sent|optional },
231 { WM_GETTEXT, sent|defwinproc|optional },
232 { WM_ERASEBKGND, sent|optional },
233 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
234 { WM_SIZE, sent|defwinproc|optional },
235 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
236 { WM_NCPAINT, sent|optional },
237 { WM_GETTEXT, sent|defwinproc|optional },
238 { WM_ERASEBKGND, sent|optional },
239 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
240 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
241 { 0 }
242 };
243
244 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
245 * for a visible popup window.
246 */
247 static const struct message WmSWP_ResizePopupSeq[] = {
248 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
249 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
250 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
251 { WM_NCPAINT, sent|optional },
252 { WM_GETTEXT, sent|defwinproc|optional },
253 { WM_ERASEBKGND, sent|optional },
254 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
255 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
256 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
257 { WM_NCPAINT, sent|optional },
258 { WM_GETTEXT, sent|defwinproc|optional },
259 { WM_ERASEBKGND, sent|optional },
260 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
261 { 0 }
262 };
263
264 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
265 * for a visible overlapped window.
266 */
267 static const struct message WmSWP_MoveSeq[] = {
268 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
269 { WM_NCPAINT, sent|optional },
270 { WM_GETTEXT, sent|defwinproc|optional },
271 { WM_ERASEBKGND, sent|optional },
272 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
273 { WM_MOVE, sent|defwinproc|wparam, 0 },
274 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
275 { 0 }
276 };
277 /* Resize with SetWindowPos(SWP_NOZORDER)
278 * for a visible overlapped window
279 * SWP_NOZORDER is stripped by the logging code
280 */
281 static const struct message WmSWP_ResizeNoZOrder[] = {
282 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
283 { WM_GETMINMAXINFO, sent|defwinproc },
284 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
285 { WM_NCPAINT, sent|optional },
286 { WM_GETTEXT, sent|defwinproc|optional },
287 { WM_ERASEBKGND, sent|optional },
288 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
289 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
290 { WM_MOVE, sent|defwinproc|optional },
291 { WM_SIZE, sent|defwinproc|optional },
292 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
293 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
294 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
295 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
296 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
297 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
298 { 0 }
299 };
300
301 /* Switch visible mdi children */
302 static const struct message WmSwitchChild[] = {
303 /* Switch MDI child */
304 { WM_MDIACTIVATE, sent },/* in the MDI client */
305 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
306 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
307 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
308 /* Deactivate 2nd MDI child */
309 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
310 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
311 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
312 /* Preparing for maximize and maximize the 1st MDI child */
313 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
314 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
315 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
316 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
317 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
318 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
319 /* Lock redraw 2nd MDI child */
320 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
321 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
322 /* Restore 2nd MDI child */
323 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
324 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
325 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
326 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
327 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
328 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
329 /* Redraw 2nd MDI child */
330 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
331 /* Redraw MDI frame */
332 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
333 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
334 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
335 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
336 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
337 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
338 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
339 { HCBT_SETFOCUS, hook },
340 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
341 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
342 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
343 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
344 { WM_SETFOCUS, sent },/* in the MDI client */
345 { HCBT_SETFOCUS, hook },
346 { WM_KILLFOCUS, sent },/* in the MDI client */
347 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
348 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
349 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
350 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
351 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
352 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
353 { 0 }
354 };
355
356 /* Switch visible not maximized mdi children */
357 static const struct message WmSwitchNotMaximizedChild[] = {
358 /* Switch not maximized MDI child */
359 { WM_MDIACTIVATE, sent },/* in the MDI client */
360 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
361 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
362 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
363 /* Deactivate 1st MDI child */
364 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
365 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
366 /* Activate 2nd MDI child */
367 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
368 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
369 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
370 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
371 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
372 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
373 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
374 { HCBT_SETFOCUS, hook },
375 { WM_KILLFOCUS, sent }, /* in the MDI client */
376 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
377 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
378 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
379 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
380 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
381 { 0 }
382 };
383
384
385 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
386 SWP_NOZORDER|SWP_FRAMECHANGED)
387 * for a visible overlapped window with WS_CLIPCHILDREN style set.
388 */
389 static const struct message WmSWP_FrameChanged_clip[] = {
390 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
391 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
392 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
393 { WM_GETTEXT, sent|parent|defwinproc|optional },
394 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
395 { WM_NCPAINT, sent }, /* wparam != 1 */
396 { WM_ERASEBKGND, sent },
397 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
398 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
399 { WM_PAINT, sent },
400 { 0 }
401 };
402 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
403 SWP_NOZORDER|SWP_FRAMECHANGED)
404 * for a visible overlapped window.
405 */
406 static const struct message WmSWP_FrameChangedDeferErase[] = {
407 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
408 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
409 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
410 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
411 { WM_PAINT, sent|parent|optional },
412 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
413 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
414 { WM_PAINT, sent },
415 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
416 { WM_ERASEBKGND, sent|beginpaint|optional },
417 { 0 }
418 };
419
420 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
421 SWP_NOZORDER|SWP_FRAMECHANGED)
422 * for a visible overlapped window without WS_CLIPCHILDREN style set.
423 */
424 static const struct message WmSWP_FrameChanged_noclip[] = {
425 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
426 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
427 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
428 { WM_GETTEXT, sent|parent|defwinproc|optional },
429 { WM_ERASEBKGND, sent|parent|optional },
430 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
431 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
432 { WM_PAINT, sent },
433 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
434 { WM_ERASEBKGND, sent|beginpaint|optional },
435 { 0 }
436 };
437
438 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
439 static const struct message WmShowOverlappedSeq[] = {
440 { WM_SHOWWINDOW, sent|wparam, 1 },
441 { WM_NCPAINT, sent|wparam|optional, 1 },
442 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
443 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
444 { WM_NCPAINT, sent|wparam|optional, 1 },
445 { WM_GETTEXT, sent|defwinproc|optional },
446 { WM_ERASEBKGND, sent|optional },
447 { HCBT_ACTIVATE, hook|optional },
448 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
449 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
450 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
451 { WM_NCPAINT, sent|wparam|optional, 1 },
452 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
453 { WM_NCACTIVATE, sent|wparam|optional, 1 },
454 { WM_GETTEXT, sent|defwinproc|optional },
455 { WM_ACTIVATE, sent|wparam|optional, 1 },
456 { HCBT_SETFOCUS, hook|optional },
457 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
458 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
459 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
460 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
461 { WM_GETTEXT, sent|optional },
462 { WM_NCPAINT, sent|wparam|optional, 1 },
463 { WM_GETTEXT, sent|defwinproc|optional },
464 { WM_ERASEBKGND, sent|optional },
465 /* Win9x adds SWP_NOZORDER below */
466 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
467 { WM_NCCALCSIZE, sent|optional },
468 { WM_GETTEXT, sent|optional },
469 { WM_NCPAINT, sent|optional },
470 { WM_ERASEBKGND, sent|optional },
471 { WM_SYNCPAINT, sent|optional },
472 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
473 * messages. Does that mean that CreateWindow doesn't set initial
474 * window dimensions for overlapped windows?
475 */
476 { WM_SIZE, sent },
477 { WM_MOVE, sent },
478 #endif
479 { WM_PAINT, sent|optional },
480 { WM_NCPAINT, sent|beginpaint|optional },
481 { 0 }
482 };
483 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
484 static const struct message WmShowMaxOverlappedSeq[] = {
485 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
486 { WM_GETMINMAXINFO, sent },
487 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
488 { WM_GETMINMAXINFO, sent|defwinproc },
489 { WM_NCCALCSIZE, sent|wparam, TRUE },
490 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
491 { HCBT_ACTIVATE, hook|optional },
492 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
493 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
494 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
495 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
496 { WM_NCACTIVATE, sent|wparam|optional, 1 },
497 { WM_GETTEXT, sent|defwinproc|optional },
498 { WM_ACTIVATE, sent|wparam|optional, 1 },
499 { HCBT_SETFOCUS, hook|optional },
500 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
501 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
502 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
503 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
504 { WM_GETTEXT, sent|optional },
505 { WM_NCPAINT, sent|wparam|optional, 1 },
506 { WM_GETTEXT, sent|defwinproc|optional },
507 { WM_ERASEBKGND, sent|optional },
508 /* Win9x adds SWP_NOZORDER below */
509 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
510 { WM_MOVE, sent|defwinproc },
511 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
512 { WM_GETTEXT, sent|optional },
513 { WM_NCCALCSIZE, sent|optional },
514 { WM_NCPAINT, sent|optional },
515 { WM_ERASEBKGND, sent|optional },
516 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
517 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
518 { WM_SYNCPAINT, sent|optional },
519 { WM_GETTITLEBARINFOEX, sent|optional },
520 { WM_PAINT, sent|optional },
521 { WM_NCPAINT, sent|beginpaint|optional },
522 { WM_ERASEBKGND, sent|beginpaint|optional },
523 { 0 }
524 };
525 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
526 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
527 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
528 { WM_GETTEXT, sent|optional },
529 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
530 { WM_GETMINMAXINFO, sent|defwinproc },
531 { WM_NCCALCSIZE, sent|wparam, TRUE },
532 { WM_NCPAINT, sent|optional },
533 { WM_GETTEXT, sent|defwinproc|optional },
534 { WM_ERASEBKGND, sent|optional },
535 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
536 { WM_MOVE, sent|defwinproc|optional },
537 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
538 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
539 { WM_NCPAINT, sent|optional },
540 { WM_ERASEBKGND, sent|optional },
541 { WM_PAINT, sent|optional },
542 { WM_GETTITLEBARINFOEX, sent|optional },
543 { WM_NCPAINT, sent|beginpaint|optional },
544 { WM_ERASEBKGND, sent|beginpaint|optional },
545 { 0 }
546 };
547 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
548 static const struct message WmShowRestoreMinOverlappedSeq[] = {
549 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
550 { WM_QUERYOPEN, sent|optional },
551 { WM_GETTEXT, sent|optional },
552 { WM_NCACTIVATE, sent|wparam|optional, 1 },
553 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
554 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
555 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
556 { WM_MOVE, sent|optional },
557 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
558 { WM_GETTEXT, sent|optional },
559 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
560 { WM_GETMINMAXINFO, sent|defwinproc|optional },
561 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
562 { HCBT_ACTIVATE, hook|optional },
563 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
564 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
565 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
566 { WM_NCACTIVATE, sent|wparam|optional, 1 },
567 { WM_GETTEXT, sent|defwinproc|optional },
568 { WM_ACTIVATE, sent|wparam|optional, 1 },
569 { HCBT_SETFOCUS, hook|optional },
570 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
571 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
572 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
573 { WM_GETTEXT, sent|optional },
574 { WM_NCPAINT, sent|wparam|optional, 1 },
575 { WM_GETTEXT, sent|defwinproc|optional },
576 { WM_ERASEBKGND, sent },
577 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
578 { WM_MOVE, sent|defwinproc },
579 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
580 { HCBT_SETFOCUS, hook|optional },
581 { WM_SETFOCUS, sent|wparam|optional, 0 },
582 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
583 { WM_NCPAINT, sent|wparam|optional, 1 },
584 { WM_ERASEBKGND, sent|optional },
585 { HCBT_SETFOCUS, hook|optional },
586 { WM_SETFOCUS, sent|wparam|optional, 0 },
587 { WM_ACTIVATE, sent|wparam, 1 },
588 { WM_GETTEXT, sent|optional },
589 { WM_PAINT, sent|optional },
590 { WM_GETTITLEBARINFOEX, sent|optional },
591 { WM_NCPAINT, sent|beginpaint|optional },
592 { WM_ERASEBKGND, sent|beginpaint|optional },
593 { 0 }
594 };
595 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
596 static const struct message WmShowMinOverlappedSeq[] = {
597 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
598 { HCBT_SETFOCUS, hook|optional },
599 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
600 { WM_KILLFOCUS, sent|optional },
601 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
602 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
603 { WM_GETTEXT, sent|optional },
604 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
605 { WM_GETMINMAXINFO, sent|defwinproc },
606 { WM_NCCALCSIZE, sent|wparam, TRUE },
607 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
608 { WM_NCPAINT, sent|optional },
609 { WM_GETTEXT, sent|defwinproc|optional },
610 { WM_WINDOWPOSCHANGED, sent },
611 { WM_MOVE, sent|defwinproc },
612 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
613 { WM_NCCALCSIZE, sent|optional },
614 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
615 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
616 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
617 { WM_NCACTIVATE, sent|wparam|optional, 0 },
618 { WM_GETTEXT, sent|defwinproc|optional },
619 { WM_ACTIVATE, sent|optional },
620 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
621
622 /* Vista sometimes restores the window right away... */
623 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
624 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
625 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
626 { WM_QUERYOPEN, sent|optional },
627 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
628 { WM_GETMINMAXINFO, sent|optional|defwinproc },
629 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
630 { HCBT_ACTIVATE, hook|optional },
631 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
632 { WM_NCACTIVATE, sent|optional },
633 { WM_GETTEXT, sent|optional },
634 { WM_ACTIVATE, sent|optional|wparam, 1 },
635 { HCBT_SETFOCUS, hook|optional },
636 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
637 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
638 { WM_SETFOCUS, sent|optional },
639 { WM_NCPAINT, sent|optional },
640 { WM_GETTEXT, sent|defwinproc|optional },
641 { WM_ERASEBKGND, sent|optional },
642 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
643 { WM_MOVE, sent|defwinproc|optional },
644 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
645 { WM_ACTIVATE, sent|optional|wparam, 1 },
646 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
647 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
648
649 { WM_PAINT, sent|optional },
650 { WM_NCPAINT, sent|beginpaint|optional },
651 { WM_ERASEBKGND, sent|beginpaint|optional },
652 { 0 }
653 };
654 /* ShowWindow(SW_HIDE) for a visible overlapped window */
655 static const struct message WmHideOverlappedSeq[] = {
656 { WM_SHOWWINDOW, sent|wparam, 0 },
657 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
658 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
659 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
660 { WM_SIZE, sent|optional }, /* XP doesn't send it */
661 { WM_MOVE, sent|optional }, /* XP doesn't send it */
662 { WM_NCACTIVATE, sent|wparam|optional, 0 },
663 { WM_ACTIVATE, sent|wparam|optional, 0 },
664 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
665 { HCBT_SETFOCUS, hook|optional },
666 { WM_KILLFOCUS, sent|wparam|optional, 0 },
667 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
668 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
669 { 0 }
670 };
671 /* DestroyWindow for a visible overlapped window */
672 static const struct message WmDestroyOverlappedSeq[] = {
673 { HCBT_DESTROYWND, hook },
674 { 0x0090, sent|optional },
675 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
676 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
677 { 0x0090, sent|optional },
678 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
679 { WM_NCACTIVATE, sent|optional|wparam, 0 },
680 { WM_ACTIVATE, sent|optional },
681 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
682 { WM_KILLFOCUS, sent|optional|wparam, 0 },
683 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
684 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
685 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
686 { WM_DESTROY, sent },
687 { WM_NCDESTROY, sent },
688 { 0 }
689 };
690 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
691 static const struct message WmCreateMaxPopupSeq[] = {
692 { HCBT_CREATEWND, hook },
693 { WM_NCCREATE, sent },
694 { WM_NCCALCSIZE, sent|wparam, 0 },
695 { WM_CREATE, sent },
696 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
697 { WM_SIZE, sent|wparam, SIZE_RESTORED },
698 { WM_MOVE, sent },
699 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
700 { WM_GETMINMAXINFO, sent },
701 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
702 { WM_NCCALCSIZE, sent|wparam, TRUE },
703 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
704 { WM_MOVE, sent|defwinproc },
705 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
706 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
707 { WM_SHOWWINDOW, sent|wparam, 1 },
708 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
709 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
710 { HCBT_ACTIVATE, hook },
711 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
712 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
713 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
714 { WM_NCPAINT, sent|wparam|optional, 1 },
715 { WM_ERASEBKGND, sent|optional },
716 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
717 { WM_ACTIVATEAPP, sent|wparam, 1 },
718 { WM_NCACTIVATE, sent },
719 { WM_ACTIVATE, sent|wparam, 1 },
720 { HCBT_SETFOCUS, hook },
721 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
722 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
723 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
724 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
725 { WM_GETTEXT, sent|optional },
726 { WM_SYNCPAINT, sent|wparam|optional, 4 },
727 { WM_NCPAINT, sent|wparam|optional, 1 },
728 { WM_ERASEBKGND, sent|optional },
729 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
730 { WM_ERASEBKGND, sent|defwinproc|optional },
731 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
732 { 0 }
733 };
734 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
735 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
736 { HCBT_CREATEWND, hook },
737 { WM_NCCREATE, sent },
738 { WM_NCCALCSIZE, sent|wparam, 0 },
739 { WM_CREATE, sent },
740 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
741 { WM_SIZE, sent|wparam, SIZE_RESTORED },
742 { WM_MOVE, sent },
743 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
744 { WM_GETMINMAXINFO, sent },
745 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
746 { WM_NCCALCSIZE, sent|wparam, TRUE },
747 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
748 { WM_MOVE, sent|defwinproc },
749 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
750 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
751 { 0 }
752 };
753 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
754 static const struct message WmShowMaxPopupResizedSeq[] = {
755 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
756 { WM_GETMINMAXINFO, sent },
757 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
758 { WM_NCCALCSIZE, sent|wparam, TRUE },
759 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
760 { HCBT_ACTIVATE, hook },
761 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
762 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
763 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
764 { WM_NCPAINT, sent|wparam|optional, 1 },
765 { WM_ERASEBKGND, sent|optional },
766 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
767 { WM_ACTIVATEAPP, sent|wparam, 1 },
768 { WM_NCACTIVATE, sent },
769 { WM_ACTIVATE, sent|wparam, 1 },
770 { HCBT_SETFOCUS, hook },
771 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
772 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
773 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
774 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
775 { WM_GETTEXT, sent|optional },
776 { WM_NCPAINT, sent|wparam|optional, 1 },
777 { WM_ERASEBKGND, sent|optional },
778 { WM_WINDOWPOSCHANGED, sent },
779 /* WinNT4.0 sends WM_MOVE */
780 { WM_MOVE, sent|defwinproc|optional },
781 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
782 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
783 { 0 }
784 };
785 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
786 static const struct message WmShowMaxPopupSeq[] = {
787 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
788 { WM_GETMINMAXINFO, sent },
789 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
790 { WM_NCCALCSIZE, sent|wparam, TRUE },
791 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
792 { HCBT_ACTIVATE, hook },
793 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
794 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
795 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
796 { WM_ACTIVATEAPP, sent|wparam, 1 },
797 { WM_NCACTIVATE, sent },
798 { WM_ACTIVATE, sent|wparam, 1 },
799 { HCBT_SETFOCUS, hook },
800 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
801 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
802 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
803 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
804 { WM_GETTEXT, sent|optional },
805 { WM_SYNCPAINT, sent|wparam|optional, 4 },
806 { WM_NCPAINT, sent|wparam|optional, 1 },
807 { WM_ERASEBKGND, sent|optional },
808 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
809 { WM_ERASEBKGND, sent|defwinproc|optional },
810 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
811 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
812 { 0 }
813 };
814 /* CreateWindow(WS_VISIBLE) for popup window */
815 static const struct message WmCreatePopupSeq[] = {
816 { HCBT_CREATEWND, hook },
817 { WM_NCCREATE, sent },
818 { WM_NCCALCSIZE, sent|wparam, 0 },
819 { WM_CREATE, sent },
820 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
821 { WM_SIZE, sent|wparam, SIZE_RESTORED },
822 { WM_MOVE, sent },
823 { WM_SHOWWINDOW, sent|wparam, 1 },
824 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
825 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
826 { HCBT_ACTIVATE, hook },
827 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
828 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
829 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
830 { WM_NCPAINT, sent|wparam|optional, 1 },
831 { WM_ERASEBKGND, sent|optional },
832 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
833 { WM_ACTIVATEAPP, sent|wparam, 1 },
834 { WM_NCACTIVATE, sent },
835 { WM_ACTIVATE, sent|wparam, 1 },
836 { HCBT_SETFOCUS, hook },
837 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
838 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
839 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
840 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
841 { WM_GETTEXT, sent|optional },
842 { WM_SYNCPAINT, sent|wparam|optional, 4 },
843 { WM_NCPAINT, sent|wparam|optional, 1 },
844 { WM_ERASEBKGND, sent|optional },
845 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
846 { 0 }
847 };
848 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
849 static const struct message WmShowVisMaxPopupSeq[] = {
850 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
851 { WM_GETMINMAXINFO, sent },
852 { WM_GETTEXT, sent|optional },
853 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
854 { WM_GETTEXT, sent|optional },
855 { WM_NCCALCSIZE, sent|wparam, TRUE },
856 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
857 { WM_NCPAINT, sent|wparam|optional, 1 },
858 { WM_ERASEBKGND, sent|optional },
859 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
860 { WM_MOVE, sent|defwinproc },
861 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
862 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
863 { 0 }
864 };
865 /* CreateWindow (for a child popup window, not initially visible) */
866 static const struct message WmCreateChildPopupSeq[] = {
867 { HCBT_CREATEWND, hook },
868 { WM_NCCREATE, sent },
869 { WM_NCCALCSIZE, sent|wparam, 0 },
870 { WM_CREATE, sent },
871 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
872 { WM_SIZE, sent|wparam, SIZE_RESTORED },
873 { WM_MOVE, sent },
874 { 0 }
875 };
876 /* CreateWindow (for a popup window, not initially visible,
877 * which sets WS_VISIBLE in WM_CREATE handler)
878 */
879 static const struct message WmCreateInvisiblePopupSeq[] = {
880 { HCBT_CREATEWND, hook },
881 { WM_NCCREATE, sent },
882 { WM_NCCALCSIZE, sent|wparam, 0 },
883 { WM_CREATE, sent },
884 { WM_STYLECHANGING, sent },
885 { WM_STYLECHANGED, sent },
886 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
887 { WM_SIZE, sent|wparam, SIZE_RESTORED },
888 { WM_MOVE, sent },
889 { 0 }
890 };
891 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
892 * for a popup window with WS_VISIBLE style set
893 */
894 static const struct message WmShowVisiblePopupSeq_2[] = {
895 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
896 { 0 }
897 };
898 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
899 * for a popup window with WS_VISIBLE style set
900 */
901 static const struct message WmShowVisiblePopupSeq_3[] = {
902 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
903 { HCBT_ACTIVATE, hook },
904 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
905 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
906 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
907 { WM_NCACTIVATE, sent },
908 { WM_ACTIVATE, sent|wparam, 1 },
909 { HCBT_SETFOCUS, hook },
910 { WM_KILLFOCUS, sent|parent },
911 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
912 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
913 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
914 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
915 { WM_SETFOCUS, sent|defwinproc },
916 { WM_GETTEXT, sent|optional },
917 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
918 { 0 }
919 };
920 /* CreateWindow (for child window, not initially visible) */
921 static const struct message WmCreateChildSeq[] = {
922 { HCBT_CREATEWND, hook },
923 { WM_NCCREATE, sent },
924 /* child is inserted into parent's child list after WM_NCCREATE returns */
925 { WM_NCCALCSIZE, sent|wparam, 0 },
926 { WM_CREATE, sent },
927 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
928 { WM_SIZE, sent|wparam, SIZE_RESTORED },
929 { WM_MOVE, sent },
930 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
931 { 0 }
932 };
933 /* CreateWindow (for maximized child window, not initially visible) */
934 static const struct message WmCreateMaximizedChildSeq[] = {
935 { HCBT_CREATEWND, hook },
936 { WM_NCCREATE, sent },
937 { WM_NCCALCSIZE, sent|wparam, 0 },
938 { WM_CREATE, sent },
939 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
940 { WM_SIZE, sent|wparam, SIZE_RESTORED },
941 { WM_MOVE, sent },
942 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
943 { WM_GETMINMAXINFO, sent },
944 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
945 { WM_NCCALCSIZE, sent|wparam, 1 },
946 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
947 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
948 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
949 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
950 { 0 }
951 };
952 /* CreateWindow (for a child window, initially visible) */
953 static const struct message WmCreateVisibleChildSeq[] = {
954 { HCBT_CREATEWND, hook },
955 { WM_NCCREATE, sent },
956 /* child is inserted into parent's child list after WM_NCCREATE returns */
957 { WM_NCCALCSIZE, sent|wparam, 0 },
958 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
959 { WM_CREATE, sent },
960 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
961 { WM_SIZE, sent|wparam, SIZE_RESTORED },
962 { WM_MOVE, sent },
963 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
964 { WM_SHOWWINDOW, sent|wparam, 1 },
965 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
966 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
967 { WM_ERASEBKGND, sent|parent|optional },
968 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
969 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
970 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
971 { 0 }
972 };
973 /* ShowWindow(SW_SHOW) for a not visible child window */
974 static const struct message WmShowChildSeq[] = {
975 { WM_SHOWWINDOW, sent|wparam, 1 },
976 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
977 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
978 { WM_ERASEBKGND, sent|parent|optional },
979 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
980 { 0 }
981 };
982 /* ShowWindow(SW_HIDE) for a visible child window */
983 static const struct message WmHideChildSeq[] = {
984 { WM_SHOWWINDOW, sent|wparam, 0 },
985 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
986 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
987 { WM_ERASEBKGND, sent|parent|optional },
988 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
989 { 0 }
990 };
991 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
992 static const struct message WmHideChildSeq2[] = {
993 { WM_SHOWWINDOW, sent|wparam, 0 },
994 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
995 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
996 { WM_ERASEBKGND, sent|parent|optional },
997 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
998 { 0 }
999 };
1000 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1001 * for a not visible child window
1002 */
1003 static const struct message WmShowChildSeq_2[] = {
1004 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1005 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1006 { WM_CHILDACTIVATE, sent },
1007 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1008 { 0 }
1009 };
1010 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1011 * for a not visible child window
1012 */
1013 static const struct message WmShowChildSeq_3[] = {
1014 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1015 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1016 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1017 { 0 }
1018 };
1019 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1020 * for a visible child window with a caption
1021 */
1022 static const struct message WmShowChildSeq_4[] = {
1023 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1024 { WM_CHILDACTIVATE, sent },
1025 { 0 }
1026 };
1027 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1028 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1029 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1030 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1031 { WM_NCCALCSIZE, sent|wparam, 1 },
1032 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1033 { WM_CHILDACTIVATE, sent|optional },
1034 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1035 { WM_MOVE, sent|defwinproc },
1036 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1037 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1038 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1039 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1040 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1041 { WM_GETTEXT, sent|optional },
1042 { 0 }
1043 };
1044 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1045 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1046 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1047 { 0 }
1048 };
1049 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1050 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1051 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1052 { WM_GETMINMAXINFO, sent },
1053 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1054 { WM_NCCALCSIZE, sent|wparam, 1 },
1055 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1056 { WM_CHILDACTIVATE, sent },
1057 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1058 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1059 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1060 { 0 }
1061 };
1062 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1063 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1064 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1065 { 0 }
1066 };
1067 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1068 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1069 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1070 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1071 { WM_NCCALCSIZE, sent|wparam, 1 },
1072 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1073 { WM_CHILDACTIVATE, sent },
1074 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1075 { WM_MOVE, sent|defwinproc },
1076 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1077 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1078 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1079 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1080 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1081 { WM_GETTEXT, sent|optional },
1082 { 0 }
1083 };
1084 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1085 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1086 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1087 { 0 }
1088 };
1089 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1090 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1091 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1092 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1093 { WM_NCCALCSIZE, sent|wparam, 1 },
1094 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1095 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1096 { WM_MOVE, sent|defwinproc },
1097 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1098 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1099 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1100 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1101 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1102 { WM_GETTEXT, sent|optional },
1103 { 0 }
1104 };
1105 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1106 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1107 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1108 { 0 }
1109 };
1110 /* ShowWindow(SW_SHOW) for child with invisible parent */
1111 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1112 { WM_SHOWWINDOW, sent|wparam, 1 },
1113 { 0 }
1114 };
1115 /* ShowWindow(SW_HIDE) for child with invisible parent */
1116 static const struct message WmHideChildInvisibleParentSeq[] = {
1117 { WM_SHOWWINDOW, sent|wparam, 0 },
1118 { 0 }
1119 };
1120 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1121 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1122 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1123 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1124 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1125 { 0 }
1126 };
1127 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1128 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1129 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1130 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1131 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1132 { 0 }
1133 };
1134 /* DestroyWindow for a visible child window */
1135 static const struct message WmDestroyChildSeq[] = {
1136 { HCBT_DESTROYWND, hook },
1137 { 0x0090, sent|optional },
1138 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1139 { WM_SHOWWINDOW, sent|wparam, 0 },
1140 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1141 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1142 { WM_ERASEBKGND, sent|parent|optional },
1143 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1144 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1145 { WM_KILLFOCUS, sent },
1146 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1147 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1148 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1149 { WM_SETFOCUS, sent|parent },
1150 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1151 { WM_DESTROY, sent },
1152 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1153 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1154 { WM_NCDESTROY, sent },
1155 { 0 }
1156 };
1157 /* visible child window destroyed by thread exit */
1158 static const struct message WmExitThreadSeq[] = {
1159 { WM_NCDESTROY, sent }, /* actually in grandchild */
1160 { WM_PAINT, sent|parent },
1161 { WM_ERASEBKGND, sent|parent|beginpaint },
1162 { 0 }
1163 };
1164 /* DestroyWindow for a visible child window with invisible parent */
1165 static const struct message WmDestroyInvisibleChildSeq[] = {
1166 { HCBT_DESTROYWND, hook },
1167 { 0x0090, sent|optional },
1168 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1169 { WM_SHOWWINDOW, sent|wparam, 0 },
1170 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1171 { WM_DESTROY, sent },
1172 { WM_NCDESTROY, sent },
1173 { 0 }
1174 };
1175 /* Moving the mouse in nonclient area */
1176 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1177 { WM_NCHITTEST, sent },
1178 { WM_SETCURSOR, sent },
1179 { WM_NCMOUSEMOVE, posted },
1180 { 0 }
1181 };
1182 /* Moving the mouse in client area */
1183 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1184 { WM_NCHITTEST, sent },
1185 { WM_SETCURSOR, sent },
1186 { WM_MOUSEMOVE, posted },
1187 { 0 }
1188 };
1189 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1190 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1191 { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1192 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1193 { WM_GETMINMAXINFO, sent|defwinproc },
1194 { WM_ENTERSIZEMOVE, sent|defwinproc },
1195 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1196 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1197 { WM_MOVE, sent|defwinproc },
1198 { WM_EXITSIZEMOVE, sent|defwinproc },
1199 { 0 }
1200 };
1201 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1202 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1203 { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1204 { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1205 { WM_GETMINMAXINFO, sent|defwinproc },
1206 { WM_ENTERSIZEMOVE, sent|defwinproc },
1207 { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1208 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1209 { WM_GETMINMAXINFO, sent|defwinproc },
1210 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1211 { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1212 { WM_GETTEXT, sent|defwinproc },
1213 { WM_ERASEBKGND, sent|defwinproc },
1214 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1215 { WM_MOVE, sent|defwinproc },
1216 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1217 { WM_EXITSIZEMOVE, sent|defwinproc },
1218 { 0 }
1219 };
1220 /* Resizing child window with MoveWindow (32) */
1221 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1222 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1223 { WM_NCCALCSIZE, sent|wparam, 1 },
1224 { WM_ERASEBKGND, sent|parent|optional },
1225 { WM_ERASEBKGND, sent|optional },
1226 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1227 { WM_MOVE, sent|defwinproc },
1228 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1229 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1230 { 0 }
1231 };
1232 /* Clicking on inactive button */
1233 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1234 { WM_NCHITTEST, sent },
1235 { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1236 { WM_MOUSEACTIVATE, sent },
1237 { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1238 { WM_SETCURSOR, sent },
1239 { WM_SETCURSOR, sent|parent|defwinproc },
1240 { WM_LBUTTONDOWN, posted },
1241 { WM_KILLFOCUS, posted|parent },
1242 { WM_SETFOCUS, posted },
1243 { WM_CTLCOLORBTN, posted|parent },
1244 { BM_SETSTATE, posted },
1245 { WM_CTLCOLORBTN, posted|parent },
1246 { WM_LBUTTONUP, posted },
1247 { BM_SETSTATE, posted },
1248 { WM_CTLCOLORBTN, posted|parent },
1249 { WM_COMMAND, posted|parent },
1250 { 0 }
1251 };
1252 /* Reparenting a button (16/32) */
1253 /* The last child (button) reparented gets topmost for its new parent. */
1254 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1255 { WM_SHOWWINDOW, sent|wparam, 0 },
1256 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1257 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1258 { WM_ERASEBKGND, sent|parent },
1259 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1260 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1261 { WM_CHILDACTIVATE, sent },
1262 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1263 { WM_MOVE, sent|defwinproc },
1264 { WM_SHOWWINDOW, sent|wparam, 1 },
1265 { 0 }
1266 };
1267 /* Creation of a custom dialog (32) */
1268 static const struct message WmCreateCustomDialogSeq[] = {
1269 { HCBT_CREATEWND, hook },
1270 { WM_GETMINMAXINFO, sent },
1271 { WM_NCCREATE, sent },
1272 { WM_NCCALCSIZE, sent|wparam, 0 },
1273 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1274 { WM_CREATE, sent },
1275 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1276 { WM_NOTIFYFORMAT, sent|optional },
1277 { WM_QUERYUISTATE, sent|optional },
1278 { WM_WINDOWPOSCHANGING, sent|optional },
1279 { WM_GETMINMAXINFO, sent|optional },
1280 { WM_NCCALCSIZE, sent|optional },
1281 { WM_WINDOWPOSCHANGED, sent|optional },
1282 { WM_SHOWWINDOW, sent|wparam, 1 },
1283 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1284 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1285 { HCBT_ACTIVATE, hook },
1286 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1287
1288
1289 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1290
1291 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1292
1293 { WM_NCACTIVATE, sent },
1294 { WM_GETTEXT, sent|optional|defwinproc },
1295 { WM_GETTEXT, sent|optional|defwinproc },
1296 { WM_GETTEXT, sent|optional|defwinproc },
1297 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1298 { WM_ACTIVATE, sent|wparam, 1 },
1299 { WM_GETTEXT, sent|optional },
1300 { WM_KILLFOCUS, sent|parent },
1301 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1302 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1303 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1304 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1305 { WM_SETFOCUS, sent },
1306 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1307 { WM_NCPAINT, sent|wparam, 1 },
1308 { WM_GETTEXT, sent|optional|defwinproc },
1309 { WM_GETTEXT, sent|optional|defwinproc },
1310 { WM_ERASEBKGND, sent },
1311 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1312 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1313 { WM_GETTEXT, sent|optional },
1314 { WM_GETTEXT, sent|optional },
1315 { WM_NCCALCSIZE, sent|optional },
1316 { WM_NCPAINT, sent|optional },
1317 { WM_GETTEXT, sent|optional|defwinproc },
1318 { WM_GETTEXT, sent|optional|defwinproc },
1319 { WM_ERASEBKGND, sent|optional },
1320 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1321 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1322 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1323 { WM_MOVE, sent },
1324 { 0 }
1325 };
1326 /* Calling EndDialog for a custom dialog (32) */
1327 static const struct message WmEndCustomDialogSeq[] = {
1328 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1329 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1330 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1331 { WM_GETTEXT, sent|optional },
1332 { HCBT_ACTIVATE, hook },
1333 { WM_NCACTIVATE, sent|wparam, 0 },
1334 { WM_GETTEXT, sent|optional|defwinproc },
1335 { WM_GETTEXT, sent|optional|defwinproc },
1336 { WM_ACTIVATE, sent|wparam, 0 },
1337 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1338 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1339 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1340 { WM_GETTEXT, sent|optional|defwinproc },
1341 { WM_GETTEXT, sent|optional|defwinproc },
1342 { HCBT_SETFOCUS, hook },
1343 { WM_KILLFOCUS, sent },
1344 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1345 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1346 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1347 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1348 { WM_SETFOCUS, sent|parent|defwinproc },
1349 { 0 }
1350 };
1351 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1352 static const struct message WmShowCustomDialogSeq[] = {
1353 { WM_SHOWWINDOW, sent|wparam, 1 },
1354 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1355 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1356 { HCBT_ACTIVATE, hook },
1357 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1358
1359 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1360
1361 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1362 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1363 { WM_NCACTIVATE, sent },
1364 { WM_ACTIVATE, sent|wparam, 1 },
1365 { WM_GETTEXT, sent|optional },
1366
1367 { WM_KILLFOCUS, sent|parent },
1368 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1369 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1370 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1371 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1372 { WM_SETFOCUS, sent },
1373 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1374 { WM_NCPAINT, sent|wparam, 1 },
1375 { WM_ERASEBKGND, sent },
1376 { WM_CTLCOLORDLG, sent|defwinproc },
1377 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1378 { 0 }
1379 };
1380 /* Creation and destruction of a modal dialog (32) */
1381 static const struct message WmModalDialogSeq[] = {
1382 { WM_CANCELMODE, sent|parent },
1383 { HCBT_SETFOCUS, hook },
1384 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1385 { WM_KILLFOCUS, sent|parent },
1386 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1387 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1388 { WM_ENABLE, sent|parent|wparam, 0 },
1389 { HCBT_CREATEWND, hook },
1390 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1391 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1392 { WM_SETFONT, sent },
1393 { WM_INITDIALOG, sent },
1394 { WM_CHANGEUISTATE, sent|optional },
1395 { WM_UPDATEUISTATE, sent|optional },
1396 { WM_SHOWWINDOW, sent },
1397 { HCBT_ACTIVATE, hook },
1398 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1399 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1400 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1401 { WM_NCACTIVATE, sent },
1402 { WM_GETTEXT, sent|optional },
1403 { WM_ACTIVATE, sent|wparam, 1 },
1404 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1405 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1406 { WM_NCPAINT, sent|optional },
1407 { WM_GETTEXT, sent|optional },
1408 { WM_ERASEBKGND, sent|optional },
1409 { WM_CTLCOLORDLG, sent|optional },
1410 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1411 { WM_GETTEXT, sent|optional },
1412 { WM_NCCALCSIZE, sent|optional },
1413 { WM_NCPAINT, sent|optional },
1414 { WM_GETTEXT, sent|optional },
1415 { WM_ERASEBKGND, sent|optional },
1416 { WM_CTLCOLORDLG, sent|optional },
1417 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1418 { WM_PAINT, sent|optional },
1419 { WM_CTLCOLORBTN, sent|optional },
1420 { WM_GETTITLEBARINFOEX, sent|optional },
1421 { WM_ENTERIDLE, sent|parent|optional },
1422 { WM_ENTERIDLE, sent|parent|optional },
1423 { WM_ENTERIDLE, sent|parent|optional },
1424 { WM_ENTERIDLE, sent|parent|optional },
1425 { WM_ENTERIDLE, sent|parent|optional },
1426 { WM_ENTERIDLE, sent|parent|optional },
1427 { WM_ENTERIDLE, sent|parent|optional },
1428 { WM_ENTERIDLE, sent|parent|optional },
1429 { WM_ENTERIDLE, sent|parent|optional },
1430 { WM_ENTERIDLE, sent|parent|optional },
1431 { WM_ENTERIDLE, sent|parent|optional },
1432 { WM_ENTERIDLE, sent|parent|optional },
1433 { WM_ENTERIDLE, sent|parent|optional },
1434 { WM_ENTERIDLE, sent|parent|optional },
1435 { WM_ENTERIDLE, sent|parent|optional },
1436 { WM_ENTERIDLE, sent|parent|optional },
1437 { WM_ENTERIDLE, sent|parent|optional },
1438 { WM_ENTERIDLE, sent|parent|optional },
1439 { WM_ENTERIDLE, sent|parent|optional },
1440 { WM_ENTERIDLE, sent|parent|optional },
1441 { WM_TIMER, sent },
1442 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1443 { WM_ENABLE, sent|parent|wparam, 1 },
1444 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1445 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1446 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1447 { WM_GETTEXT, sent|optional },
1448 { HCBT_ACTIVATE, hook },
1449 { WM_NCACTIVATE, sent|wparam, 0 },
1450 { WM_GETTEXT, sent|optional },
1451 { WM_ACTIVATE, sent|wparam, 0 },
1452 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1453 { WM_WINDOWPOSCHANGING, sent|optional },
1454 { WM_WINDOWPOSCHANGED, sent|optional },
1455 { HCBT_SETFOCUS, hook },
1456 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1457 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1458 { WM_SETFOCUS, sent|parent|defwinproc },
1459 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1460 { HCBT_DESTROYWND, hook },
1461 { 0x0090, sent|optional },
1462 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1463 { WM_DESTROY, sent },
1464 { WM_NCDESTROY, sent },
1465 { 0 }
1466 };
1467 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1468 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1469 /* (inside dialog proc, handling WM_INITDIALOG) */
1470 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1471 { WM_NCCALCSIZE, sent },
1472 { WM_NCACTIVATE, sent|parent|wparam, 0 },
1473 { WM_GETTEXT, sent|defwinproc },
1474 { WM_ACTIVATE, sent|parent|wparam, 0 },
1475 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1476 { WM_WINDOWPOSCHANGING, sent|parent },
1477 { WM_NCACTIVATE, sent|wparam, 1 },
1478 { WM_ACTIVATE, sent|wparam, 1 },
1479 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1480 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1481 /* (setting focus) */
1482 { WM_SHOWWINDOW, sent|wparam, 1 },
1483 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1484 { WM_NCPAINT, sent },
1485 { WM_GETTEXT, sent|defwinproc },
1486 { WM_ERASEBKGND, sent },
1487 { WM_CTLCOLORDLG, sent|defwinproc },
1488 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1489 { WM_PAINT, sent },
1490 /* (bunch of WM_CTLCOLOR* for each control) */
1491 { WM_PAINT, sent|parent },
1492 { WM_ENTERIDLE, sent|parent|wparam, 0 },
1493 { WM_SETCURSOR, sent|parent },
1494 { 0 }
1495 };
1496 /* SetMenu for NonVisible windows with size change*/
1497 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1498 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1499 { WM_NCCALCSIZE, sent|wparam, 1 },
1500 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1501 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1502 { WM_MOVE, sent|defwinproc },
1503 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1504 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1505 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1506 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1507 { WM_GETTEXT, sent|optional },
1508 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1509 { 0 }
1510 };
1511 /* SetMenu for NonVisible windows with no size change */
1512 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1513 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1514 { WM_NCCALCSIZE, sent|wparam, 1 },
1515 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1516 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1517 { 0 }
1518 };
1519 /* SetMenu for Visible windows with size change */
1520 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1521 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1522 { WM_NCCALCSIZE, sent|wparam, 1 },
1523 { 0x0093, sent|defwinproc|optional },
1524 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1525 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1526 { 0x0093, sent|defwinproc|optional },
1527 { 0x0093, sent|defwinproc|optional },
1528 { 0x0091, sent|defwinproc|optional },
1529 { 0x0092, sent|defwinproc|optional },
1530 { WM_GETTEXT, sent|defwinproc|optional },
1531 { WM_ERASEBKGND, sent|optional },
1532 { WM_ACTIVATE, sent|optional },
1533 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1534 { WM_MOVE, sent|defwinproc },
1535 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1536 { 0x0093, sent|optional },
1537 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1538 { 0x0093, sent|defwinproc|optional },
1539 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1540 { 0x0093, sent|defwinproc|optional },
1541 { 0x0093, sent|defwinproc|optional },
1542 { 0x0091, sent|defwinproc|optional },
1543 { 0x0092, sent|defwinproc|optional },
1544 { WM_ERASEBKGND, sent|optional },
1545 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1546 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1547 { 0 }
1548 };
1549 /* SetMenu for Visible windows with no size change */
1550 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1551 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1552 { WM_NCCALCSIZE, sent|wparam, 1 },
1553 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1554 { WM_GETTEXT, sent|defwinproc|optional },
1555 { WM_ERASEBKGND, sent|optional },
1556 { WM_ACTIVATE, sent|optional },
1557 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1558 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1559 { 0 }
1560 };
1561 /* DrawMenuBar for a visible window */
1562 static const struct message WmDrawMenuBarSeq[] =
1563 {
1564 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1565 { WM_NCCALCSIZE, sent|wparam, 1 },
1566 { 0x0093, sent|defwinproc|optional },
1567 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1568 { 0x0093, sent|defwinproc|optional },
1569 { 0x0093, sent|defwinproc|optional },
1570 { 0x0091, sent|defwinproc|optional },
1571 { 0x0092, sent|defwinproc|optional },
1572 { WM_GETTEXT, sent|defwinproc|optional },
1573 { WM_ERASEBKGND, sent|optional },
1574 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1575 { 0x0093, sent|optional },
1576 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1577 { 0 }
1578 };
1579
1580 static const struct message WmSetRedrawFalseSeq[] =
1581 {
1582 { WM_SETREDRAW, sent|wparam, 0 },
1583 { 0 }
1584 };
1585
1586 static const struct message WmSetRedrawTrueSeq[] =
1587 {
1588 { WM_SETREDRAW, sent|wparam, 1 },
1589 { 0 }
1590 };
1591
1592 static const struct message WmEnableWindowSeq_1[] =
1593 {
1594 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1595 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1596 { HCBT_SETFOCUS, hook|optional },
1597 { WM_KILLFOCUS, sent|optional },
1598 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1599 { 0 }
1600 };
1601
1602 static const struct message WmEnableWindowSeq_2[] =
1603 {
1604 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1605 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1606 { 0 }
1607 };
1608
1609 static const struct message WmGetScrollRangeSeq[] =
1610 {
1611 { SBM_GETRANGE, sent },
1612 { 0 }
1613 };
1614 static const struct message WmGetScrollInfoSeq[] =
1615 {
1616 { SBM_GETSCROLLINFO, sent },
1617 { 0 }
1618 };
1619 static const struct message WmSetScrollRangeSeq[] =
1620 {
1621 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1622 sends SBM_SETSCROLLINFO.
1623 */
1624 { SBM_SETSCROLLINFO, sent },
1625 { 0 }
1626 };
1627 /* SetScrollRange for a window without a non-client area */
1628 static const struct message WmSetScrollRangeHSeq_empty[] =
1629 {
1630 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1631 { 0 }
1632 };
1633 static const struct message WmSetScrollRangeVSeq_empty[] =
1634 {
1635 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1636 { 0 }
1637 };
1638 static const struct message WmSetScrollRangeHVSeq[] =
1639 {
1640 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1641 { WM_NCCALCSIZE, sent|wparam, 1 },
1642 { WM_GETTEXT, sent|defwinproc|optional },
1643 { WM_ERASEBKGND, sent|optional },
1644 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1645 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1646 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1647 { 0 }
1648 };
1649 /* SetScrollRange for a window with a non-client area */
1650 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1651 {
1652 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1653 { WM_NCCALCSIZE, sent|wparam, 1 },
1654 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1655 { WM_NCPAINT, sent|optional },
1656 { WM_STYLECHANGING, sent|defwinproc|optional },
1657 { WM_STYLECHANGED, sent|defwinproc|optional },
1658 { WM_STYLECHANGING, sent|defwinproc|optional },
1659 { WM_STYLECHANGED, sent|defwinproc|optional },
1660 { WM_STYLECHANGING, sent|defwinproc|optional },
1661 { WM_STYLECHANGED, sent|defwinproc|optional },
1662 { WM_STYLECHANGING, sent|defwinproc|optional },
1663 { WM_STYLECHANGED, sent|defwinproc|optional },
1664 { WM_GETTEXT, sent|defwinproc|optional },
1665 { WM_GETTEXT, sent|defwinproc|optional },
1666 { WM_ERASEBKGND, sent|optional },
1667 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1668 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1669 { WM_SIZE, sent|defwinproc|optional },
1670 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1671 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1672 { WM_GETTEXT, sent|optional },
1673 { WM_GETTEXT, sent|optional },
1674 { WM_GETTEXT, sent|optional },
1675 { WM_GETTEXT, sent|optional },
1676 { 0 }
1677 };
1678 /* test if we receive the right sequence of messages */
1679 /* after calling ShowWindow( SW_SHOWNA) */
1680 static const struct message WmSHOWNAChildInvisParInvis[] = {
1681 { WM_SHOWWINDOW, sent|wparam, 1 },
1682 { 0 }
1683 };
1684 static const struct message WmSHOWNAChildVisParInvis[] = {
1685 { WM_SHOWWINDOW, sent|wparam, 1 },
1686 { 0 }
1687 };
1688 static const struct message WmSHOWNAChildVisParVis[] = {
1689 { WM_SHOWWINDOW, sent|wparam, 1 },
1690 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1691 { 0 }
1692 };
1693 static const struct message WmSHOWNAChildInvisParVis[] = {
1694 { WM_SHOWWINDOW, sent|wparam, 1 },
1695 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1696 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1697 { WM_ERASEBKGND, sent|optional },
1698 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1699 { 0 }
1700 };
1701 static const struct message WmSHOWNATopVisible[] = {
1702 { WM_SHOWWINDOW, sent|wparam, 1 },
1703 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1704 { WM_NCPAINT, sent|wparam|optional, 1 },
1705 { WM_GETTEXT, sent|defwinproc|optional },
1706 { WM_ERASEBKGND, sent|optional },
1707 { WM_WINDOWPOSCHANGED, sent|optional },
1708 { 0 }
1709 };
1710 static const struct message WmSHOWNATopInvisible[] = {
1711 { WM_NOTIFYFORMAT, sent|optional },
1712 { WM_QUERYUISTATE, sent|optional },
1713 { WM_WINDOWPOSCHANGING, sent|optional },
1714 { WM_GETMINMAXINFO, sent|optional },
1715 { WM_NCCALCSIZE, sent|optional },
1716 { WM_WINDOWPOSCHANGED, sent|optional },
1717 { WM_SHOWWINDOW, sent|wparam, 1 },
1718 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1719 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1720 { WM_NCPAINT, sent|wparam|optional, 1 },
1721 { WM_GETTEXT, sent|defwinproc|optional },
1722 { WM_ERASEBKGND, sent|optional },
1723 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1724 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1725 { WM_NCPAINT, sent|wparam|optional, 1 },
1726 { WM_ERASEBKGND, sent|optional },
1727 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1728 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1729 { WM_MOVE, sent },
1730 { 0 }
1731 };
1732
1733 static const struct message WmTrackPopupMenu[] = {
1734 { HCBT_CREATEWND, hook },
1735 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1736 { WM_INITMENU, sent|lparam, 0, 0 },
1737 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1738 { 0x0093, sent|optional },
1739 { 0x0094, sent|optional },
1740 { 0x0094, sent|optional },
1741 { WM_ENTERIDLE, sent|wparam, 2 },
1742 { WM_CAPTURECHANGED, sent },
1743 { HCBT_DESTROYWND, hook },
1744 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1745 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1746 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1747 { 0 }
1748 };
1749
1750 static const struct message WmTrackPopupMenuEmpty[] = {
1751 { HCBT_CREATEWND, hook },
1752 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1753 { WM_INITMENU, sent|lparam, 0, 0 },
1754 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1755 { 0x0093, sent|optional },
1756 { 0x0094, sent|optional },
1757 { 0x0094, sent|optional },
1758 { WM_CAPTURECHANGED, sent },
1759 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1760 { HCBT_DESTROYWND, hook },
1761 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1762 { 0 }
1763 };
1764
1765 static BOOL after_end_dialog, test_def_id, paint_loop_done;
1766 static int sequence_cnt, sequence_size;
1767 static struct recvd_message* sequence;
1768 static int log_all_parent_messages;
1769 static CRITICAL_SECTION sequence_cs;
1770
1771 /* user32 functions */
1772 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1773 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1774 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1775 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1776 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1777 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1778 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1779 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
1780 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
1781 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
1782 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
1783 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
1784 /* kernel32 functions */
1785 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1786
1787 static void init_procs(void)
1788 {
1789 HMODULE user32 = GetModuleHandleA("user32.dll");
1790 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1791
1792 #define GET_PROC(dll, func) \
1793 p ## func = (void*)GetProcAddress(dll, #func); \
1794 if(!p ## func) { \
1795 trace("GetProcAddress(%s) failed\n", #func); \
1796 }
1797
1798 GET_PROC(user32, GetAncestor)
1799 GET_PROC(user32, GetMenuInfo)
1800 GET_PROC(user32, NotifyWinEvent)
1801 GET_PROC(user32, SetMenuInfo)
1802 GET_PROC(user32, SetWinEventHook)
1803 GET_PROC(user32, TrackMouseEvent)
1804 GET_PROC(user32, UnhookWinEvent)
1805 GET_PROC(user32, GetMonitorInfoA)
1806 GET_PROC(user32, MonitorFromPoint)
1807 GET_PROC(user32, UpdateLayeredWindow)
1808 GET_PROC(user32, SetSystemTimer)
1809 GET_PROC(user32, KillSystemTimer)
1810
1811 GET_PROC(kernel32, GetCPInfoExA)
1812
1813 #undef GET_PROC
1814 }
1815
1816 static const char *get_winpos_flags(UINT flags)
1817 {
1818 static char buffer[300];
1819
1820 buffer[0] = 0;
1821 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1822 DUMP( SWP_SHOWWINDOW );
1823 DUMP( SWP_HIDEWINDOW );
1824 DUMP( SWP_NOACTIVATE );
1825 DUMP( SWP_FRAMECHANGED );
1826 DUMP( SWP_NOCOPYBITS );
1827 DUMP( SWP_NOOWNERZORDER );
1828 DUMP( SWP_NOSENDCHANGING );
1829 DUMP( SWP_DEFERERASE );
1830 DUMP( SWP_ASYNCWINDOWPOS );
1831 DUMP( SWP_NOZORDER );
1832 DUMP( SWP_NOREDRAW );
1833 DUMP( SWP_NOSIZE );
1834 DUMP( SWP_NOMOVE );
1835 DUMP( SWP_NOCLIENTSIZE );
1836 DUMP( SWP_NOCLIENTMOVE );
1837 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1838 return buffer + 1;
1839 #undef DUMP
1840 }
1841
1842 static BOOL ignore_message( UINT message )
1843 {
1844 /* these are always ignored */
1845 return (message >= 0xc000 ||
1846 message == WM_GETICON ||
1847 message == WM_GETOBJECT ||
1848 message == WM_TIMECHANGE ||
1849 message == WM_DISPLAYCHANGE ||
1850 message == WM_DEVICECHANGE ||
1851 message == WM_DWMNCRENDERINGCHANGED);
1852 }
1853
1854
1855 #define add_message(msg) add_message_(__LINE__,msg);
1856 static void add_message_(int line, const struct recvd_message *msg)
1857 {
1858 struct recvd_message *seq;
1859
1860 EnterCriticalSection( &sequence_cs );
1861 if (!sequence)
1862 {
1863 sequence_size = 10;
1864 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1865 }
1866 if (sequence_cnt == sequence_size)
1867 {
1868 sequence_size *= 2;
1869 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1870 }
1871 assert(sequence);
1872
1873 seq = &sequence[sequence_cnt++];
1874 seq->hwnd = msg->hwnd;
1875 seq->message = msg->message;
1876 seq->flags = msg->flags;
1877 seq->wParam = msg->wParam;
1878 seq->lParam = msg->lParam;
1879 seq->line = line;
1880 seq->descr = msg->descr;
1881 seq->output[0] = 0;
1882 LeaveCriticalSection( &sequence_cs );
1883
1884 if (msg->descr)
1885 {
1886 if (msg->flags & hook)
1887 {
1888 static const char * const CBT_code_name[10] =
1889 {
1890 "HCBT_MOVESIZE",
1891 "HCBT_MINMAX",
1892 "HCBT_QS",
1893 "HCBT_CREATEWND",
1894 "HCBT_DESTROYWND",
1895 "HCBT_ACTIVATE",
1896 "HCBT_CLICKSKIPPED",
1897 "HCBT_KEYSKIPPED",
1898 "HCBT_SYSCOMMAND",
1899 "HCBT_SETFOCUS"
1900 };
1901 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1902
1903 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1904 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1905 }
1906 else if (msg->flags & winevent_hook)
1907 {
1908 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1909 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1910 }
1911 else
1912 {
1913 switch (msg->message)
1914 {
1915 case WM_WINDOWPOSCHANGING:
1916 case WM_WINDOWPOSCHANGED:
1917 {
1918 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1919
1920 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1921 msg->descr, msg->hwnd,
1922 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1923 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1924 winpos->x, winpos->y, winpos->cx, winpos->cy,
1925 get_winpos_flags(winpos->flags) );
1926
1927 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1928 * in the high word for internal purposes
1929 */
1930 seq->wParam = winpos->flags & 0xffff;
1931 /* We are not interested in the flags that don't match under XP and Win9x */
1932 seq->wParam &= ~SWP_NOZORDER;
1933 break;
1934 }
1935
1936 case WM_DRAWITEM:
1937 {
1938 DRAW_ITEM_STRUCT di;
1939 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1940
1941 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1942 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1943 dis->itemID, dis->itemAction, dis->itemState);
1944
1945 di.u.lp = 0;
1946 di.u.item.type = dis->CtlType;
1947 di.u.item.ctl_id = dis->CtlID;
1948 if (dis->CtlType == ODT_LISTBOX ||
1949 dis->CtlType == ODT_COMBOBOX ||
1950 dis->CtlType == ODT_MENU)
1951 di.u.item.item_id = dis->itemID;
1952 di.u.item.action = dis->itemAction;
1953 di.u.item.state = dis->itemState;
1954
1955 seq->lParam = di.u.lp;
1956 break;
1957 }
1958 default:
1959 if (msg->message >= 0xc000) return; /* ignore registered messages */
1960 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1961 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1962 }
1963 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1964 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1965 }
1966 }
1967 }
1968
1969 /* try to make sure pending X events have been processed before continuing */
1970 static void flush_events(void)
1971 {
1972 MSG msg;
1973 int diff = 200;
1974 int min_timeout = 100;
1975 DWORD time = GetTickCount() + diff;
1976
1977 while (diff > 0)
1978 {
1979 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1980 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1981 diff = time - GetTickCount();
1982 }
1983 }
1984
1985 static void flush_sequence(void)
1986 {
1987 EnterCriticalSection( &sequence_cs );
1988 HeapFree(GetProcessHeap(), 0, sequence);
1989 sequence = 0;
1990 sequence_cnt = sequence_size = 0;
1991 LeaveCriticalSection( &sequence_cs );
1992 }
1993
1994 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1995 {
1996 const struct recvd_message *actual = sequence;
1997 unsigned int count = 0;
1998
1999 trace_(file, line)("Failed sequence %s:\n", context );
2000 while (expected->message && actual->message)
2001 {
2002 if (actual->output[0])
2003 {
2004 if (expected->flags & hook)
2005 {
2006 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2007 count, expected->message, actual->output );
2008 }
2009 else if (expected->flags & winevent_hook)
2010 {
2011 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2012 count, expected->message, actual->output );
2013 }
2014 else if (expected->flags & kbd_hook)
2015 {
2016 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2017 count, expected->message, actual->output );
2018 }
2019 else
2020 {
2021 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2022 count, expected->message, actual->output );
2023 }
2024 }
2025
2026 if (expected->message == actual->message)
2027 {
2028 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2029 (expected->flags & optional))
2030 {
2031 /* don't match messages if their defwinproc status differs */
2032 expected++;
2033 }
2034 else
2035 {
2036 expected++;
2037 actual++;
2038 }
2039 }
2040 /* silently drop winevent messages if there is no support for them */
2041 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2042 expected++;
2043 else
2044 {
2045 expected++;
2046 actual++;
2047 }
2048 count++;
2049 }
2050
2051 /* optional trailing messages */
2052 while (expected->message && ((expected->flags & optional) ||
2053 ((expected->flags & winevent_hook) && !hEvent_hook)))
2054 {
2055 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2056 expected++;
2057 count++;
2058 }
2059
2060 if (expected->message)
2061 {
2062 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2063 return;
2064 }
2065
2066 while (actual->message && actual->output[0])
2067 {
2068 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2069 actual++;
2070 count++;
2071 }
2072 }
2073
2074 #define ok_sequence( exp, contx, todo) \
2075 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2076
2077
2078 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2079 const char *file, int line)
2080 {
2081 static const struct recvd_message end_of_sequence;
2082 const struct message *expected = expected_list;
2083 const struct recvd_message *actual;
2084 int failcount = 0, dump = 0;
2085 unsigned int count = 0;
2086
2087 add_message(&end_of_sequence);
2088
2089 actual = sequence;
2090
2091 while (expected->message && actual->message)
2092 {
2093 if (expected->message == actual->message &&
2094 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2095 {
2096 if (expected->flags & wparam)
2097 {
2098 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2099 {
2100 todo_wine {
2101 failcount ++;
2102 if (strcmp(winetest_platform, "wine")) dump++;
2103 ok_( file, line) (FALSE,
2104 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2105 context, count, expected->message, expected->wParam, actual->wParam);
2106 }
2107 }
2108 else
2109 {
2110 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2111 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2112 context, count, expected->message, expected->wParam, actual->wParam);
2113 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2114 }
2115
2116 }
2117 if (expected->flags & lparam)
2118 {
2119 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2120 {
2121 todo_wine {
2122 failcount ++;
2123 if (strcmp(winetest_platform, "wine")) dump++;
2124 ok_( file, line) (FALSE,
2125 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2126 context, count, expected->message, expected->lParam, actual->lParam);
2127 }
2128 }
2129 else
2130 {
2131 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2132 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2133 context, count, expected->message, expected->lParam, actual->lParam);
2134 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2135 }
2136 }
2137 if ((expected->flags & optional) &&
2138 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2139 {
2140 /* don't match optional messages if their defwinproc or parent status differs */
2141 expected++;
2142 count++;
2143 continue;
2144 }
2145 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2146 {
2147 todo_wine {
2148 failcount ++;
2149 if (strcmp(winetest_platform, "wine")) dump++;
2150 ok_( file, line) (FALSE,
2151 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2152 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2153 }
2154 }
2155 else
2156 {
2157 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2158 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2159 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2160 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2161 }
2162
2163 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2164 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2165 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2166 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2167
2168 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2169 "%s: %u: the msg 0x%04x should have been %s\n",
2170 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2171 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2172
2173 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2174 "%s: %u: the msg 0x%04x was expected in %s\n",
2175 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2176 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2177
2178 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2179 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2180 context, count, expected->message);
2181 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2182
2183 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2184 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2185 context, count, expected->message);
2186 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2187
2188 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2189 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2190 context, count, expected->message);
2191 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2192
2193 expected++;
2194 actual++;
2195 }
2196 /* silently drop hook messages if there is no support for them */
2197 else if ((expected->flags & optional) ||
2198 ((expected->flags & hook) && !hCBT_hook) ||
2199 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2200 ((expected->flags & kbd_hook) && !hKBD_hook))
2201 expected++;
2202 else if (todo)
2203 {
2204 failcount++;
2205 todo_wine {
2206 if (strcmp(winetest_platform, "wine")) dump++;
2207 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2208 context, count, expected->message, actual->message);
2209 }
2210 goto done;
2211 }
2212 else
2213 {
2214 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2215 context, count, expected->message, actual->message);
2216 dump++;
2217 expected++;
2218 actual++;
2219 }
2220 count++;
2221 }
2222
2223 /* skip all optional trailing messages */
2224 while (expected->message && ((expected->flags & optional) ||
2225 ((expected->flags & hook) && !hCBT_hook) ||
2226 ((expected->flags & winevent_hook) && !hEvent_hook)))
2227 expected++;
2228
2229 if (todo)
2230 {
2231 todo_wine {
2232 if (expected->message || actual->message) {
2233 failcount++;
2234 if (strcmp(winetest_platform, "wine")) dump++;
2235 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2236 context, count, expected->message, actual->message);
2237 }
2238 }
2239 }
2240 else
2241 {
2242 if (expected->message || actual->message)
2243 {
2244 dump++;
2245 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2246 context, count, expected->message, actual->message);
2247 }
2248 }
2249 if( todo && !failcount) /* succeeded yet marked todo */
2250 todo_wine {
2251 if (!strcmp(winetest_platform, "wine")) dump++;
2252 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2253 }
2254
2255 done:
2256 if (dump) dump_sequence(expected_list, context, file, line);
2257 flush_sequence();
2258 }
2259
2260 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2261
2262 /******************************** MDI test **********************************/
2263
2264 /* CreateWindow for MDI frame window, initially visible */
2265 static const struct message WmCreateMDIframeSeq[] = {
2266 { HCBT_CREATEWND, hook },
2267 { WM_GETMINMAXINFO, sent },
2268 { WM_NCCREATE, sent },
2269 { WM_NCCALCSIZE, sent|wparam, 0 },
2270 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2271 { WM_CREATE, sent },
2272 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2273 { WM_NOTIFYFORMAT, sent|optional },
2274 { WM_QUERYUISTATE, sent|optional },
2275 { WM_WINDOWPOSCHANGING, sent|optional },
2276 { WM_GETMINMAXINFO, sent|optional },
2277 { WM_NCCALCSIZE, sent|optional },
2278 { WM_WINDOWPOSCHANGED, sent|optional },
2279 { WM_SHOWWINDOW, sent|wparam, 1 },
2280 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2281 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2282 { HCBT_ACTIVATE, hook },
2283 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2284 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2285 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2286 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2287 { WM_NCACTIVATE, sent },
2288 { WM_GETTEXT, sent|defwinproc|optional },
2289 { WM_ACTIVATE, sent|wparam, 1 },
2290 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2291 { HCBT_SETFOCUS, hook },
2292 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2293 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2294 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2295 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2296 /* Win9x adds SWP_NOZORDER below */
2297 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2298 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2299 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2300 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2301 { WM_MOVE, sent },
2302 { 0 }
2303 };
2304 /* DestroyWindow for MDI frame window, initially visible */
2305 static const struct message WmDestroyMDIframeSeq[] = {
2306 { HCBT_DESTROYWND, hook },
2307 { 0x0090, sent|optional },
2308 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2309 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2310 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2311 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2312 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2313 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2314 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2315 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2316 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2317 { WM_DESTROY, sent },
2318 { WM_NCDESTROY, sent },
2319 { 0 }
2320 };
2321 /* CreateWindow for MDI client window, initially visible */
2322 static const struct message WmCreateMDIclientSeq[] = {
2323 { HCBT_CREATEWND, hook },
2324 { WM_NCCREATE, sent },
2325 { WM_NCCALCSIZE, sent|wparam, 0 },
2326 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2327 { WM_CREATE, sent },
2328 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2329 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2330 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2331 { WM_MOVE, sent },
2332 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2333 { WM_SHOWWINDOW, sent|wparam, 1 },
2334 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2335 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2336 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2337 { 0 }
2338 };
2339 /* ShowWindow(SW_SHOW) for MDI client window */
2340 static const struct message WmShowMDIclientSeq[] = {
2341 { WM_SHOWWINDOW, sent|wparam, 1 },
2342 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2343 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2344 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2345 { 0 }
2346 };
2347 /* ShowWindow(SW_HIDE) for MDI client window */
2348 static const struct message WmHideMDIclientSeq[] = {
2349 { WM_SHOWWINDOW, sent|wparam, 0 },
2350 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2351 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2352 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2353 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2354 { 0 }
2355 };
2356 /* DestroyWindow for MDI client window, initially visible */
2357 static const struct message WmDestroyMDIclientSeq[] = {
2358 { HCBT_DESTROYWND, hook },
2359 { 0x0090, sent|optional },
2360 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2361 { WM_SHOWWINDOW, sent|wparam, 0 },
2362 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2363 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2364 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2365 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2366 { WM_DESTROY, sent },
2367 { WM_NCDESTROY, sent },
2368 { 0 }
2369 };
2370 /* CreateWindow for MDI child window, initially visible */
2371 static const struct message WmCreateMDIchildVisibleSeq[] = {
2372 { HCBT_CREATEWND, hook },
2373 { WM_NCCREATE, sent },
2374 { WM_NCCALCSIZE, sent|wparam, 0 },
2375 { WM_CREATE, sent },
2376 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2377 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2378 { WM_MOVE, sent },
2379 /* Win2k sends wparam set to
2380 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2381 * while Win9x doesn't bother to set child window id according to
2382 * CLIENTCREATESTRUCT.idFirstChild
2383 */
2384 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2385 { WM_SHOWWINDOW, sent|wparam, 1 },
2386 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2387 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2388 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2389 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2390 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2391 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2392 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2393
2394 /* Win9x: message sequence terminates here. */
2395
2396 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2397 { HCBT_SETFOCUS, hook }, /* in MDI client */
2398 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2399 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2400 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2401 { WM_SETFOCUS, sent }, /* in MDI client */
2402 { HCBT_SETFOCUS, hook },
2403 { WM_KILLFOCUS, sent }, /* in MDI client */
2404 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2405 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2406 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2407 { WM_SETFOCUS, sent|defwinproc },
2408 { WM_MDIACTIVATE, sent|defwinproc },
2409 { 0 }
2410 };
2411 /* CreateWindow for MDI child window with invisible parent */
2412 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2413 { HCBT_CREATEWND, hook },
2414 { WM_GETMINMAXINFO, sent },
2415 { WM_NCCREATE, sent },
2416 { WM_NCCALCSIZE, sent|wparam, 0 },
2417 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2418 { WM_CREATE, sent },
2419 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2420 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2421 { WM_MOVE, sent },
2422 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2423 { WM_SHOWWINDOW, sent|wparam, 1 },
2424 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2425 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2426 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2427 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2428
2429 /* Win9x: message sequence terminates here. */
2430
2431 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2432 { HCBT_SETFOCUS, hook }, /* in MDI client */
2433 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2434 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2435 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2436 { WM_SETFOCUS, sent }, /* in MDI client */
2437 { HCBT_SETFOCUS, hook },
2438 { WM_KILLFOCUS, sent }, /* in MDI client */
2439 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2440 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2441 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2442 { WM_SETFOCUS, sent|defwinproc },
2443 { WM_MDIACTIVATE, sent|defwinproc },
2444 { 0 }
2445 };
2446 /* DestroyWindow for MDI child window, initially visible */
2447 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2448 { HCBT_DESTROYWND, hook },
2449 /* Win2k sends wparam set to
2450 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2451 * while Win9x doesn't bother to set child window id according to
2452 * CLIENTCREATESTRUCT.idFirstChild
2453 */
2454 { 0x0090, sent|optional },
2455 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2456 { WM_SHOWWINDOW, sent|wparam, 0 },
2457 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2458 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2459 { WM_ERASEBKGND, sent|parent|optional },
2460 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2461
2462 /* { WM_DESTROY, sent }
2463 * Win9x: message sequence terminates here.
2464 */
2465
2466 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2467 { WM_KILLFOCUS, sent },
2468 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2469 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2470 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2471 { WM_SETFOCUS, sent }, /* in MDI client */
2472
2473 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2474 { WM_KILLFOCUS, sent }, /* in MDI client */
2475 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2476 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2477 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2478 { WM_SETFOCUS, sent }, /* in MDI client */
2479
2480 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2481
2482 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2483 { WM_KILLFOCUS, sent },
2484 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2485 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2486 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2487 { WM_SETFOCUS, sent }, /* in MDI client */
2488
2489 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2490 { WM_KILLFOCUS, sent }, /* in MDI client */
2491 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2492 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2493 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2494 { WM_SETFOCUS, sent }, /* in MDI client */
2495
2496 { WM_DESTROY, sent },
2497
2498 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2499 { WM_KILLFOCUS, sent },
2500 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2501 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2502 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2503 { WM_SETFOCUS, sent }, /* in MDI client */
2504
2505 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2506 { WM_KILLFOCUS, sent }, /* in MDI client */
2507 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2508 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2509 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2510 { WM_SETFOCUS, sent }, /* in MDI client */
2511
2512 { WM_NCDESTROY, sent },
2513 { 0 }
2514 };
2515 /* CreateWindow for MDI child window, initially invisible */
2516 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2517 { HCBT_CREATEWND, hook },
2518 { WM_NCCREATE, sent },
2519 { WM_NCCALCSIZE, sent|wparam, 0 },
2520 { WM_CREATE, sent },
2521 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2522 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2523 { WM_MOVE, sent },
2524 /* Win2k sends wparam set to
2525 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2526 * while Win9x doesn't bother to set child window id according to
2527 * CLIENTCREATESTRUCT.idFirstChild
2528 */
2529 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2530 { 0 }
2531 };
2532 /* DestroyWindow for MDI child window, initially invisible */
2533 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2534 { HCBT_DESTROYWND, hook },
2535 /* Win2k sends wparam set to
2536 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2537 * while Win9x doesn't bother to set child window id according to
2538 * CLIENTCREATESTRUCT.idFirstChild
2539 */
2540 { 0x0090, sent|optional },
2541 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2542 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2543 { WM_DESTROY, sent },
2544 { WM_NCDESTROY, sent },
2545 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2546 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2547 { 0 }
2548 };
2549 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2550 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2551 { HCBT_CREATEWND, hook },
2552 { WM_NCCREATE, sent },
2553 { WM_NCCALCSIZE, sent|wparam, 0 },
2554 { WM_CREATE, sent },
2555 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2556 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2557 { WM_MOVE, sent },
2558 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2559 { WM_GETMINMAXINFO, sent },
2560 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2561 { WM_NCCALCSIZE, sent|wparam, 1 },
2562 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2563 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2564 /* in MDI frame */
2565 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2566 { WM_NCCALCSIZE, sent|wparam, 1 },
2567 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2568 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2569 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2570 /* Win2k sends wparam set to
2571 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2572 * while Win9x doesn't bother to set child window id according to
2573 * CLIENTCREATESTRUCT.idFirstChild
2574 */
2575 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2576 { WM_SHOWWINDOW, sent|wparam, 1 },
2577 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2578 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2579 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2580 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2581 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2582 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2583 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2584
2585 /* Win9x: message sequence terminates here. */
2586
2587 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2588 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2589 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2590 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2591 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2592 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2593 { HCBT_SETFOCUS, hook|optional },
2594 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2595 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2596 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2597 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2598 { WM_SETFOCUS, sent|defwinproc|optional },
2599 { WM_MDIACTIVATE, sent|defwinproc|optional },
2600 /* in MDI frame */
2601 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2602 { WM_NCCALCSIZE, sent|wparam, 1 },
2603 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2604 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2605 { 0 }
2606 };
2607 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2608 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2609 /* restore the 1st MDI child */
2610 { WM_SETREDRAW, sent|wparam, 0 },
2611 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2612 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2613 { WM_NCCALCSIZE, sent|wparam, 1 },
2614 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2615 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2616 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2617 /* in MDI frame */
2618 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2619 { WM_NCCALCSIZE, sent|wparam, 1 },
2620 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2621 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2622 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2623 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2624 /* create the 2nd MDI child */
2625 { HCBT_CREATEWND, hook },
2626 { WM_NCCREATE, sent },
2627 { WM_NCCALCSIZE, sent|wparam, 0 },
2628 { WM_CREATE, sent },
2629 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2630 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2631 { WM_MOVE, sent },
2632 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2633 { WM_GETMINMAXINFO, sent },
2634 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2635 { WM_NCCALCSIZE, sent|wparam, 1 },
2636 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2637 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2638 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2639 /* in MDI frame */
2640 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2641 { WM_NCCALCSIZE, sent|wparam, 1 },
2642 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2643 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2644 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2645 /* Win2k sends wparam set to
2646 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2647 * while Win9x doesn't bother to set child window id according to
2648 * CLIENTCREATESTRUCT.idFirstChild
2649 */
2650 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2651 { WM_SHOWWINDOW, sent|wparam, 1 },
2652 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2653 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2654 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2655 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2656 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2657 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2658
2659 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2660 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2661
2662 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2663
2664 /* Win9x: message sequence terminates here. */
2665
2666 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2667 { HCBT_SETFOCUS, hook },
2668 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2669 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2670 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2671 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2672 { WM_SETFOCUS, sent }, /* in MDI client */
2673 { HCBT_SETFOCUS, hook },
2674 { WM_KILLFOCUS, sent }, /* in MDI client */
2675 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2676 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2677 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2678 { WM_SETFOCUS, sent|defwinproc },
2679
2680 { WM_MDIACTIVATE, sent|defwinproc },
2681 /* in MDI frame */
2682 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2683 { WM_NCCALCSIZE, sent|wparam, 1 },
2684 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2685 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2686 { 0 }
2687 };
2688 /* WM_MDICREATE MDI child window, initially visible and maximized */
2689 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2690 { WM_MDICREATE, sent },
2691 { HCBT_CREATEWND, hook },
2692 { WM_NCCREATE, sent },
2693 { WM_NCCALCSIZE, sent|wparam, 0 },
2694 { WM_CREATE, sent },
2695 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2696 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2697 { WM_MOVE, sent },
2698 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2699 { WM_GETMINMAXINFO, sent },
2700 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2701 { WM_NCCALCSIZE, sent|wparam, 1 },
2702 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2703 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2704
2705 /* in MDI frame */
2706 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2707 { WM_NCCALCSIZE, sent|wparam, 1 },
2708 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2709 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2710 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2711
2712 /* Win2k sends wparam set to
2713 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2714 * while Win9x doesn't bother to set child window id according to
2715 * CLIENTCREATESTRUCT.idFirstChild
2716 */
2717 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2718 { WM_SHOWWINDOW, sent|wparam, 1 },
2719 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2720
2721 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2722
2723 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2724 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2725 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2726
2727 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2728 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2729
2730 /* Win9x: message sequence terminates here. */
2731
2732 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2733 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2734 { HCBT_SETFOCUS, hook }, /* in MDI client */
2735 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2736 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2737 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2738 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2739 { HCBT_SETFOCUS, hook|optional },
2740 { WM_KILLFOCUS, sent }, /* in MDI client */
2741 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2742 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2743 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2744 { WM_SETFOCUS, sent|defwinproc },
2745
2746 { WM_MDIACTIVATE, sent|defwinproc },
2747
2748 /* in MDI child */
2749 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2750 { WM_NCCALCSIZE, sent|wparam, 1 },
2751 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2752 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2753
2754 /* in MDI frame */
2755 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2756 { WM_NCCALCSIZE, sent|wparam, 1 },
2757 { 0x0093, sent|defwinproc|optional },
2758 { 0x0093, sent|defwinproc|optional },
2759 { 0x0093, sent|defwinproc|optional },
2760 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2761 { WM_MOVE, sent|defwinproc },
2762 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2763
2764 /* in MDI client */
2765 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2766 { WM_NCCALCSIZE, sent|wparam, 1 },
2767 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2768 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2769
2770 /* in MDI child */
2771 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2772 { WM_NCCALCSIZE, sent|wparam, 1 },
2773 { 0x0093, sent|optional },
2774 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2775 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2776
2777 { 0x0093, sent|optional },
2778 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2779 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2780 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2781 { 0x0093, sent|defwinproc|optional },
2782 { 0x0093, sent|defwinproc|optional },
2783 { 0x0093, sent|defwinproc|optional },
2784 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2785 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2786
2787 { 0 }
2788 };
2789 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2790 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2791 { HCBT_CREATEWND, hook },
2792 { WM_GETMINMAXINFO, sent },
2793 { WM_NCCREATE, sent },
2794 { WM_NCCALCSIZE, sent|wparam, 0 },
2795 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2796 { WM_CREATE, sent },
2797 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2798 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2799 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2800 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2801 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2802 { WM_MOVE, sent },
2803 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2804 { WM_GETMINMAXINFO, sent },
2805 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2806 { WM_GETMINMAXINFO, sent|defwinproc },
2807 { WM_NCCALCSIZE, sent|wparam, 1 },
2808 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
2809 { WM_MOVE, sent|defwinproc },
2810 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2811 /* in MDI frame */
2812 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2813 { WM_NCCALCSIZE, sent|wparam, 1 },
2814 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2815 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2816 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2817 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2818 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2819 /* Win2k sends wparam set to
2820 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2821 * while Win9x doesn't bother to set child window id according to
2822 * CLIENTCREATESTRUCT.idFirstChild
2823 */
2824 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2825 { 0 }
2826 };
2827 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2828 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2829 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2830 { HCBT_SYSCOMMAND, hook },
2831 { WM_CLOSE, sent|defwinproc },
2832 { WM_MDIDESTROY, sent }, /* in MDI client */
2833
2834 /* bring the 1st MDI child to top */
2835 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2836 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2837
2838 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2839
2840 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2841 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2842 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2843
2844 /* maximize the 1st MDI child */
2845 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2846 { WM_GETMINMAXINFO, sent|defwinproc },
2847 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2848 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2849 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2850 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2851 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2852
2853 /* restore the 2nd MDI child */
2854 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2855 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2856 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2857 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2858
2859 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2860
2861 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2862 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2863
2864 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2865
2866 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2867 /* in MDI frame */
2868 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2869 { WM_NCCALCSIZE, sent|wparam, 1 },
2870 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2871 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2872 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2873
2874 /* bring the 1st MDI child to top */
2875 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2876 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2877 { HCBT_SETFOCUS, hook },
2878 { WM_KILLFOCUS, sent|defwinproc },
2879 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2880 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2881 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2882 { WM_SETFOCUS, sent }, /* in MDI client */
2883 { HCBT_SETFOCUS, hook },
2884 { WM_KILLFOCUS, sent }, /* in MDI client */
2885 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2886 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2887 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2888 { WM_SETFOCUS, sent|defwinproc },
2889 { WM_MDIACTIVATE, sent|defwinproc },
2890 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2891
2892 /* apparently ShowWindow(SW_SHOW) on an MDI client */
2893 { WM_SHOWWINDOW, sent|wparam, 1 },
2894 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2895 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2896 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2897 { WM_MDIREFRESHMENU, sent },
2898
2899 { HCBT_DESTROYWND, hook },
2900 /* Win2k sends wparam set to
2901 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2902 * while Win9x doesn't bother to set child window id according to
2903 * CLIENTCREATESTRUCT.idFirstChild
2904 */
2905 { 0x0090, sent|defwinproc|optional },
2906 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2907 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2908 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2909 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2910 { WM_ERASEBKGND, sent|parent|optional },
2911 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2912
2913 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2914 { WM_DESTROY, sent|defwinproc },
2915 { WM_NCDESTROY, sent|defwinproc },
2916 { 0 }
2917 };
2918 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2919 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2920 { WM_MDIDESTROY, sent }, /* in MDI client */
2921 { WM_SHOWWINDOW, sent|wparam, 0 },
2922 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2923 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2924 { WM_ERASEBKGND, sent|parent|optional },
2925 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2926
2927 { HCBT_SETFOCUS, hook },
2928 { WM_KILLFOCUS, sent },
2929 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2930 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2931 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2932 { WM_SETFOCUS, sent }, /* in MDI client */
2933 { HCBT_SETFOCUS, hook },
2934 { WM_KILLFOCUS, sent }, /* in MDI client */
2935 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2936 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2937 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2938 { WM_SETFOCUS, sent },
2939
2940 /* in MDI child */
2941 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2942 { WM_NCCALCSIZE, sent|wparam, 1 },
2943 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2944 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2945
2946 /* in MDI frame */
2947 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2948 { WM_NCCALCSIZE, sent|wparam, 1 },
2949 { 0x0093, sent|defwinproc|optional },
2950 { 0x0093, sent|defwinproc|optional },
2951 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2952 { WM_MOVE, sent|defwinproc },
2953 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2954
2955 /* in MDI client */
2956 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2957 { WM_NCCALCSIZE, sent|wparam, 1 },
2958 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2959 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2960
2961 /* in MDI child */
2962 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2963 { WM_NCCALCSIZE, sent|wparam, 1 },
2964 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2965 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2966
2967 /* in MDI child */
2968 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2969 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2970 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2971 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2972
2973 /* in MDI frame */
2974 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2975 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2976 { 0x0093, sent|defwinproc|optional },
2977 { 0x0093, sent|defwinproc|optional },
2978 { 0x0093, sent|defwinproc|optional },
2979 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2980 { WM_MOVE, sent|defwinproc },
2981 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2982
2983 /* in MDI client */
2984 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2985 { WM_NCCALCSIZE, sent|wparam, 1 },
2986 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2987 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2988
2989 /* in MDI child */
2990 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2991 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2992 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2993 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2994 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2995 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2996
2997 { 0x0093, sent|defwinproc|optional },
2998 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2999 { 0x0093, sent|defwinproc|optional },
3000 { 0x0093, sent|defwinproc|optional },
3001 { 0x0093, sent|defwinproc|optional },
3002 { 0x0093, sent|optional },
3003
3004 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3005 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3006 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3007 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3008 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3009
3010 /* in MDI frame */
3011 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3012 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3013 { 0x0093, sent|defwinproc|optional },
3014 { 0x0093, sent|defwinproc|optional },
3015 { 0x0093, sent|defwinproc|optional },
3016 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3017 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3018 { 0x0093, sent|optional },
3019
3020 { WM_NCACTIVATE, sent|wparam, 0 },
3021 { WM_MDIACTIVATE, sent },
3022
3023 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3024 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3025 { WM_NCCALCSIZE, sent|wparam, 1 },
3026
3027 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3028
3029 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3030 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3031 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3032
3033 /* in MDI child */
3034 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3035 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3036 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3037 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3038
3039 /* in MDI frame */
3040 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3041 { WM_NCCALCSIZE, sent|wparam, 1 },
3042 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3043 { WM_MOVE, sent|defwinproc },
3044 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3045
3046 /* in MDI client */
3047 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3048 { WM_NCCALCSIZE, sent|wparam, 1 },
3049 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3050 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3051 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3052 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3053 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3054 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3055 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3056
3057 { HCBT_SETFOCUS, hook },
3058 { WM_KILLFOCUS, sent },
3059 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3060 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3061 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3062 { WM_SETFOCUS, sent }, /* in MDI client */
3063
3064 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3065
3066 { HCBT_DESTROYWND, hook },
3067 /* Win2k sends wparam set to
3068 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3069 * while Win9x doesn't bother to set child window id according to
3070 * CLIENTCREATESTRUCT.idFirstChild
3071 */
3072 { 0x0090, sent|optional },
3073 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3074
3075 { WM_SHOWWINDOW, sent|wparam, 0 },
3076 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3077 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3078 { WM_ERASEBKGND, sent|parent|optional },
3079 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3080
3081 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3082 { WM_DESTROY, sent },
3083 { WM_NCDESTROY, sent },
3084 { 0 }
3085 };
3086 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3087 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3088 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3089 { WM_GETMINMAXINFO, sent },
3090 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3091 { WM_NCCALCSIZE, sent|wparam, 1 },
3092 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3093 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3094
3095 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3096 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3097 { HCBT_SETFOCUS, hook|optional },
3098 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3099 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3100 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3101 { HCBT_SETFOCUS, hook|optional },
3102 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3103 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3104 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3105 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3106 { WM_SETFOCUS, sent|optional|defwinproc },
3107 { WM_MDIACTIVATE, sent|optional|defwinproc },
3108 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3109 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3110 /* in MDI frame */
3111 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3112 { WM_NCCALCSIZE, sent|wparam, 1 },
3113 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3114 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3115 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3116 { 0 }
3117 };
3118 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3119 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3120 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3121 { WM_GETMINMAXINFO, sent },
3122 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3123 { WM_GETMINMAXINFO, sent|defwinproc },
3124 { WM_NCCALCSIZE, sent|wparam, 1 },
3125 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3126 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3127
3128 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3129 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3130 { HCBT_SETFOCUS, hook|optional },
3131 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3132 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3133 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3134 { HCBT_SETFOCUS, hook|optional },
3135 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3136 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3137 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3138 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3139 { WM_SETFOCUS, sent|defwinproc|optional },
3140 { WM_MDIACTIVATE, sent|defwinproc|optional },
3141 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3142 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3143 { 0 }
3144 };
3145 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3146 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3147 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3148 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3149 { WM_GETMINMAXINFO, sent },
3150 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3151 { WM_GETMINMAXINFO, sent|defwinproc },
3152 { WM_NCCALCSIZE, sent|wparam, 1 },
3153 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3154 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3155 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3156 { WM_MOVE, sent|defwinproc },
3157 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3158
3159 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3160 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3161 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3162 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3163 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3164 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3165 /* in MDI frame */
3166 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3167 { WM_NCCALCSIZE, sent|wparam, 1 },
3168 { 0x0093, sent|defwinproc|optional },
3169 { 0x0094, sent|defwinproc|optional },
3170 { 0x0094, sent|defwinproc|optional },
3171 { 0x0094, sent|defwinproc|optional },
3172 { 0x0094, sent|defwinproc|optional },
3173 { 0x0093, sent|defwinproc|optional },
3174 { 0x0093, sent|defwinproc|optional },
3175 { 0x0091, sent|defwinproc|optional },
3176 { 0x0092, sent|defwinproc|optional },
3177 { 0x0092, sent|defwinproc|optional },
3178 { 0x0092, sent|defwinproc|optional },
3179 { 0x0092, sent|defwinproc|optional },
3180 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3181 { WM_MOVE, sent|defwinproc },
3182 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3183 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3184 /* in MDI client */
3185 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3186 { WM_NCCALCSIZE, sent|wparam, 1 },
3187 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3188 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3189 /* in MDI child */
3190 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3191 { WM_GETMINMAXINFO, sent|defwinproc },
3192 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3193 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3194 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3195 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3196 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3197 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3198 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3199 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3200 /* in MDI frame */
3201 { 0x0093, sent|optional },
3202 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3203 { 0x0093, sent|defwinproc|optional },
3204 { 0x0093, sent|defwinproc|optional },
3205 { 0x0093, sent|defwinproc|optional },
3206 { 0x0091, sent|defwinproc|optional },
3207 { 0x0092, sent|defwinproc|optional },
3208 { 0x0092, sent|defwinproc|optional },
3209 { 0x0092, sent|defwinproc|optional },
3210 { 0x0092, sent|defwinproc|optional },
3211 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3212 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3213 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3214 { 0 }
3215 };
3216 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3217 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3218 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3219 { WM_GETMINMAXINFO, sent },
3220 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3221 { WM_NCCALCSIZE, sent|wparam, 1 },
3222 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3223 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3224 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3225 /* in MDI frame */
3226 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3227 { WM_NCCALCSIZE, sent|wparam, 1 },
3228 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3229 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3230 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3231 { 0 }
3232 };
3233 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3234 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3235 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3236 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3237 { WM_NCCALCSIZE, sent|wparam, 1 },
3238 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3239 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3240 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3241 /* in MDI frame */
3242 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3243 { WM_NCCALCSIZE, sent|wparam, 1 },
3244 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3245 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3246 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3247 { 0 }
3248 };
3249 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3250 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3251 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3252 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3253 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3254 { WM_NCCALCSIZE, sent|wparam, 1 },
3255 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3256 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3257 { WM_MOVE, sent|defwinproc },
3258 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3259 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3260 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3261 { HCBT_SETFOCUS, hook },
3262 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3263 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3264 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3265 { WM_SETFOCUS, sent },
3266 { 0 }
3267 };
3268 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3269 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3270 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3271 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3272 { WM_NCCALCSIZE, sent|wparam, 1 },
3273 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3274 { WM_MOVE, sent|defwinproc },
3275 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3276 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3277 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3278 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3279 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3280 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3281 { 0 }
3282 };
3283 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3284 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3285 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3286 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3287 { WM_NCCALCSIZE, sent|wparam, 1 },
3288 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3289 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3290 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3291 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3292 /* in MDI frame */
3293 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3294 { WM_NCCALCSIZE, sent|wparam, 1 },
3295 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3296 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3297 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3298 { 0 }
3299 };
3300
3301 static HWND mdi_client;
3302 static WNDPROC old_mdi_client_proc;
3303
3304 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3305 {
3306 struct recvd_message msg;
3307
3308 /* do not log painting messages */
3309 if (message != WM_PAINT &&
3310 message != WM_NCPAINT &&
3311 message != WM_SYNCPAINT &&
3312 message != WM_ERASEBKGND &&
3313 message != WM_NCHITTEST &&
3314 message != WM_GETTEXT &&
3315 message != WM_MDIGETACTIVE &&
3316 !ignore_message( message ))
3317 {
3318 msg.hwnd = hwnd;
3319 msg.message = message;
3320 msg.flags = sent|wparam|lparam;
3321 msg.wParam = wParam;
3322 msg.lParam = lParam;
3323 msg.descr = "mdi client";
3324 add_message(&msg);
3325 }
3326
3327 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3328 }
3329
3330 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3331 {
3332 static LONG defwndproc_counter = 0;
3333 LRESULT ret;
3334 struct recvd_message msg;
3335
3336 /* do not log painting messages */
3337 if (message != WM_PAINT &&
3338 message != WM_NCPAINT &&
3339 message != WM_SYNCPAINT &&
3340 message != WM_ERASEBKGND &&
3341 message != WM_NCHITTEST &&
3342 message != WM_GETTEXT &&
3343 !ignore_message( message ))
3344 {
3345 switch (message)
3346 {
3347 case WM_MDIACTIVATE:
3348 {
3349 HWND active, client = GetParent(hwnd);
3350
3351 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3352
3353 if (hwnd == (HWND)lParam) /* if we are being activated */
3354 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3355 else
3356 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3357 break;
3358 }
3359 }
3360
3361 msg.hwnd = hwnd;
3362 msg.message = message;
3363 msg.flags = sent|wparam|lparam;
3364 if (defwndproc_counter) msg.flags |= defwinproc;
3365 msg.wParam = wParam;
3366 msg.lParam = lParam;
3367 msg.descr = "mdi child";
3368 add_message(&msg);
3369 }
3370
3371 defwndproc_counter++;
3372 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3373 defwndproc_counter--;
3374
3375 return ret;
3376 }
3377
3378 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3379 {
3380 static LONG defwndproc_counter = 0;
3381 LRESULT ret;
3382 struct recvd_message msg;
3383
3384 /* do not log painting messages */
3385 if (message != WM_PAINT &&
3386 message != WM_NCPAINT &&
3387 message != WM_SYNCPAINT &&
3388 message != WM_ERASEBKGND &&
3389 message != WM_NCHITTEST &&
3390 message != WM_GETTEXT &&
3391 !ignore_message( message ))
3392 {
3393 msg.hwnd = hwnd;
3394 msg.message = message;
3395 msg.flags = sent|wparam|lparam;
3396 if (defwndproc_counter) msg.flags |= defwinproc;
3397 msg.wParam = wParam;
3398 msg.lParam = lParam;
3399 msg.descr = "mdi frame";
3400 add_message(&msg);
3401 }
3402
3403 defwndproc_counter++;
3404 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3405 defwndproc_counter--;
3406
3407 return ret;
3408 }
3409
3410 static BOOL mdi_RegisterWindowClasses(void)
3411 {
3412 WNDCLASSA cls;
3413
3414 cls.style = 0;
3415 cls.lpfnWndProc = mdi_frame_wnd_proc;
3416 cls.cbClsExtra = 0;
3417 cls.cbWndExtra = 0;
3418 cls.hInstance = GetModuleHandleA(0);
3419 cls.hIcon = 0;
3420 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3421 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3422 cls.lpszMenuName = NULL;
3423 cls.lpszClassName = "MDI_frame_class";
3424 if (!RegisterClassA(&cls)) return FALSE;
3425
3426 cls.lpfnWndProc = mdi_child_wnd_proc;
3427 cls.lpszClassName = "MDI_child_class";
3428 if (!RegisterClassA(&cls)) return FALSE;
3429
3430 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3431 old_mdi_client_proc = cls.lpfnWndProc;
3432 cls.hInstance = GetModuleHandleA(0);
3433 cls.lpfnWndProc = mdi_client_hook_proc;
3434 cls.lpszClassName = "MDI_client_class";
3435 if (!RegisterClassA(&cls)) assert(0);
3436
3437 return TRUE;
3438 }
3439
3440 static void test_mdi_messages(void)
3441 {
3442 MDICREATESTRUCTA mdi_cs;
3443 CLIENTCREATESTRUCT client_cs;
3444 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3445 BOOL zoomed;
3446 RECT rc;
3447 HMENU hMenu = CreateMenu();
3448
3449 if (!mdi_RegisterWindowClasses()) assert(0);
3450
3451 flush_sequence();
3452
3453 trace("creating MDI frame window\n");
3454 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3455 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3456 WS_MAXIMIZEBOX | WS_VISIBLE,
3457 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3458 GetDesktopWindow(), hMenu,
3459 GetModuleHandleA(0), NULL);
3460 assert(mdi_frame);
3461 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3462
3463 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3464 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3465
3466 trace("creating MDI client window\n");
3467 GetClientRect(mdi_frame, &rc);
3468 client_cs.hWindowMenu = 0;
3469 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3470 mdi_client = CreateWindowExA(0, "MDI_client_class",
3471 NULL,
3472 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3473 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3474 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3475 assert(mdi_client);
3476 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3477
3478 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3479 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3480
3481 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3482 ok(!active_child, "wrong active MDI child %p\n", active_child);
3483 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3484
3485 SetFocus(0);
3486 flush_sequence();
3487
3488 trace("creating invisible MDI child window\n");
3489 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3490 WS_CHILD,
3491 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3492 mdi_client, 0, GetModuleHandleA(0), NULL);
3493 assert(mdi_child);
3494
3495 flush_sequence();
3496 ShowWindow(mdi_child, SW_SHOWNORMAL);
3497 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3498
3499 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3500 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3501
3502 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3503 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3504
3505 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3506 ok(!active_child, "wrong active MDI child %p\n", active_child);
3507 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3508
3509 ShowWindow(mdi_child, SW_HIDE);
3510 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3511 flush_sequence();
3512
3513 ShowWindow(mdi_child, SW_SHOW);
3514 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3515
3516 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3517 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3518
3519 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3520 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3521
3522 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3523 ok(!active_child, "wrong active MDI child %p\n", active_child);
3524 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3525
3526 DestroyWindow(mdi_child);
3527 flush_sequence();
3528
3529 trace("creating visible MDI child window\n");
3530 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3531 WS_CHILD | WS_VISIBLE,
3532 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3533 mdi_client, 0, GetModuleHandleA(0), NULL);
3534 assert(mdi_child);
3535 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3536
3537 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3538 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3539
3540 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3541 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3542
3543 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3544 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3545 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3546 flush_sequence();
3547
3548 DestroyWindow(mdi_child);
3549 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3550
3551 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3552 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3553
3554 /* Win2k: MDI client still returns a just destroyed child as active
3555 * Win9x: MDI client returns 0
3556 */
3557 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3558 ok(active_child == mdi_child || /* win2k */
3559 !active_child, /* win9x */
3560 "wrong active MDI child %p\n", active_child);
3561 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3562
3563 flush_sequence();
3564
3565 trace("creating invisible MDI child window\n");
3566 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3567 WS_CHILD,
3568 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3569 mdi_client, 0, GetModuleHandleA(0), NULL);
3570 assert(mdi_child2);
3571 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3572
3573 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3574 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3575
3576 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3577 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3578
3579 /* Win2k: MDI client still returns a just destroyed child as active
3580 * Win9x: MDI client returns mdi_child2
3581 */
3582 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3583 ok(active_child == mdi_child || /* win2k */
3584 active_child == mdi_child2, /* win9x */
3585 "wrong active MDI child %p\n", active_child);
3586 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3587 flush_sequence();
3588
3589 ShowWindow(mdi_child2, SW_MAXIMIZE);
3590 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3591
3592 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3593 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3594
3595 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3596 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3597 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3598 flush_sequence();
3599
3600 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3601 ok(GetFocus() == mdi_child2 || /* win2k */
3602 GetFocus() == 0, /* win9x */
3603 "wrong focus window %p\n", GetFocus());
3604
3605 SetFocus(0);
3606 flush_sequence();
3607
3608 ShowWindow(mdi_child2, SW_HIDE);
3609 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3610
3611 ShowWindow(mdi_child2, SW_RESTORE);
3612 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3613 flush_sequence();
3614
3615 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3616 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3617
3618 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3619 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3620 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3621 flush_sequence();
3622
3623 SetFocus(0);
3624 flush_sequence();
3625
3626 ShowWindow(mdi_child2, SW_HIDE);
3627 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3628
3629 ShowWindow(mdi_child2, SW_SHOW);
3630 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3631
3632 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3633 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3634
3635 ShowWindow(mdi_child2, SW_MAXIMIZE);
3636 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3637
3638 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3639 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3640
3641 ShowWindow(mdi_child2, SW_RESTORE);
3642 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3643
3644 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3645 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3646
3647 ShowWindow(mdi_child2, SW_MINIMIZE);
3648 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3649
3650 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3651 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3652
3653 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3654 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3655 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3656 flush_sequence();
3657
3658 ShowWindow(mdi_child2, SW_RESTORE);
3659 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3660
3661 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3662 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3663
3664 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3665 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3666 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3667 flush_sequence();
3668
3669 SetFocus(0);
3670 flush_sequence();
3671
3672 ShowWindow(mdi_child2, SW_HIDE);
3673 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3674
3675 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3676 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3677
3678 DestroyWindow(mdi_child2);
3679 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3680
3681 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3682 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3683
3684 /* test for maximized MDI children */
3685 trace("creating maximized visible MDI child window 1\n");
3686 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3687 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3688 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3689 mdi_client, 0, GetModuleHandleA(0), NULL);
3690 assert(mdi_child);
3691 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3692 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3693
3694 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3695 ok(GetFocus() == mdi_child || /* win2k */
3696 GetFocus() == 0, /* win9x */
3697 "wrong focus window %p\n", GetFocus());
3698
3699 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3700 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3701 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3702 flush_sequence();
3703
3704 trace("creating maximized visible MDI child window 2\n");
3705 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3706 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3707 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3708 mdi_client, 0, GetModuleHandleA(0), NULL);
3709 assert(mdi_child2);
3710 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3711 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3712 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3713
3714 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3715 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3716
3717 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3718 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3719 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3720 flush_sequence();
3721
3722 trace("destroying maximized visible MDI child window 2\n");
3723 DestroyWindow(mdi_child2);
3724 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3725
3726 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3727
3728 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3729 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3730
3731 /* Win2k: MDI client still returns a just destroyed child as active
3732 * Win9x: MDI client returns 0
3733 */
3734 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3735 ok(active_child == mdi_child2 || /* win2k */
3736 !active_child, /* win9x */
3737 "wrong active MDI child %p\n", active_child);
3738 flush_sequence();
3739
3740 ShowWindow(mdi_child, SW_MAXIMIZE);
3741 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3742 flush_sequence();
3743
3744 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3745 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3746
3747 trace("re-creating maximized visible MDI child window 2\n");
3748 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3749 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3750 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3751 mdi_client, 0, GetModuleHandleA(0), NULL);
3752 assert(mdi_child2);
3753 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3754 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3755 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3756
3757 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3758 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3759
3760 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3761 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3762 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3763 flush_sequence();
3764
3765 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3766 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3767 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3768
3769 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3770 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3771 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3772
3773 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3774 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3775 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3776 flush_sequence();
3777
3778 DestroyWindow(mdi_child);
3779 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3780
3781 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3782 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3783
3784 /* Win2k: MDI client still returns a just destroyed child as active
3785 * Win9x: MDI client returns 0
3786 */
3787 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3788 ok(active_child == mdi_child || /* win2k */
3789 !active_child, /* win9x */
3790 "wrong active MDI child %p\n", active_child);
3791 flush_sequence();
3792
3793 trace("creating maximized invisible MDI child window\n");
3794 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3795 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3796 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3797 mdi_client, 0, GetModuleHandleA(0), NULL);
3798 assert(mdi_child2);
3799 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3800 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3801 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3802 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3803
3804 /* Win2k: MDI client still returns a just destroyed child as active
3805 * Win9x: MDI client returns 0
3806 */
3807 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3808 ok(active_child == mdi_child || /* win2k */
3809 !active_child || active_child == mdi_child2, /* win9x */
3810 "wrong active MDI child %p\n", active_child);
3811 flush_sequence();
3812
3813 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3814 ShowWindow(mdi_child2, SW_MAXIMIZE);
3815 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3816 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3817 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3818 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3819
3820 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3821 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3822 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3823 flush_sequence();
3824
3825 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3826 flush_sequence();
3827
3828 /* end of test for maximized MDI children */
3829 SetFocus(0);
3830 flush_sequence();
3831 trace("creating maximized visible MDI child window 1(Switch test)\n");
3832 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3833 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3834 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3835 mdi_client, 0, GetModuleHandleA(0), NULL);
3836 assert(mdi_child);
3837 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3838 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3839
3840 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3841 ok(GetFocus() == mdi_child || /* win2k */
3842 GetFocus() == 0, /* win9x */
3843 "wrong focus window %p(Switch test)\n", GetFocus());
3844
3845 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3846 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3847 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3848 flush_sequence();
3849
3850 trace("creating maximized visible MDI child window 2(Switch test)\n");
3851 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3852 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3853 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3854 mdi_client, 0, GetModuleHandleA(0), NULL);
3855 assert(mdi_child2);
3856 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3857
3858 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3859 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3860
3861 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3862 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3863
3864 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3865 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3866 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3867 flush_sequence();
3868
3869 trace("Switch child window.\n");
3870 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3871 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3872 trace("end of test for switch maximized MDI children\n");
3873 flush_sequence();
3874
3875 /* Prepare for switching test of not maximized MDI children */
3876 ShowWindow( mdi_child, SW_NORMAL );
3877 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3878 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3879 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3880 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3881 flush_sequence();
3882
3883 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3884 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3885 trace("end of test for switch not maximized MDI children\n");
3886 flush_sequence();
3887
3888 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3889 flush_sequence();
3890
3891 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3892 flush_sequence();
3893
3894 SetFocus(0);
3895 flush_sequence();
3896 /* end of tests for switch maximized/not maximized MDI children */
3897
3898 mdi_cs.szClass = "MDI_child_Class";
3899 mdi_cs.szTitle = "MDI child";
3900 mdi_cs.hOwner = GetModuleHandleA(0);
3901 mdi_cs.x = 0;
3902 mdi_cs.y = 0;
3903 mdi_cs.cx = CW_USEDEFAULT;
3904 mdi_cs.cy = CW_USEDEFAULT;
3905 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3906 mdi_cs.lParam = 0;
3907 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3908 ok(mdi_child != 0, "MDI child creation failed\n");
3909 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3910
3911 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3912
3913 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3914 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3915
3916 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3917 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3918 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3919
3920 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3921 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3922 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3923 flush_sequence();
3924
3925 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3926 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3927
3928 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3929 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3930 ok(!active_child, "wrong active MDI child %p\n", active_child);
3931
3932 SetFocus(0);
3933 flush_sequence();
3934
3935 DestroyWindow(mdi_client);
3936 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3937
3938 /* test maximization of MDI child with invisible parent */
3939 client_cs.hWindowMenu = 0;
3940 mdi_client = CreateWindowA("MDI_client_class",
3941 NULL,
3942 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3943 0, 0, 660, 430,
3944 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3945 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3946
3947 ShowWindow(mdi_client, SW_HIDE);
3948 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3949
3950 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3951 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3952 0, 0, 650, 440,
3953 mdi_client, 0, GetModuleHandleA(0), NULL);
3954 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3955
3956 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3957 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3958 zoomed = IsZoomed(mdi_child);
3959 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3960
3961 ShowWindow(mdi_client, SW_SHOW);
3962 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3963
3964 DestroyWindow(mdi_child);
3965 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3966
3967 /* end of test for maximization of MDI child with invisible parent */
3968
3969 DestroyWindow(mdi_client);
3970 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3971
3972 DestroyWindow(mdi_frame);
3973 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3974 }
3975 /************************* End of MDI test **********************************/
3976
3977 static void test_WM_SETREDRAW(HWND hwnd)
3978 {
3979 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3980
3981 flush_events();
3982 flush_sequence();
3983
3984 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3985 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3986
3987 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3988 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3989
3990 flush_sequence();
3991 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3992 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3993
3994 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3995 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3996
3997 /* restore original WS_VISIBLE state */
3998 SetWindowLongA(hwnd, GWL_STYLE, style);
3999
4000 flush_events();
4001 flush_sequence();
4002 }
4003
4004 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4005 {
4006 struct recvd_message msg;
4007
4008 if (ignore_message( message )) return 0;
4009
4010 switch (message)
4011 {
4012 /* ignore */
4013 case WM_MOUSEMOVE:
4014 case WM_NCMOUSEMOVE:
4015 case WM_NCMOUSELEAVE:
4016 case WM_SETCURSOR:
4017 return 0;
4018 case WM_NCHITTEST:
4019 return HTCLIENT;
4020 }
4021
4022 msg.hwnd = hwnd;
4023 msg.message = message;
4024 msg.flags = sent|wparam|lparam;
4025 msg.wParam = wParam;
4026 msg.lParam = lParam;
4027 msg.descr = "dialog";
4028 add_message(&msg);
4029
4030 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4031 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4032 return 0;
4033 }
4034
4035 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4036 {
4037 DWORD style, exstyle;
4038 INT xmin, xmax;
4039 BOOL ret;
4040
4041 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4042 style = GetWindowLongA(hwnd, GWL_STYLE);
4043 /* do not be confused by WS_DLGFRAME set */
4044 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4045
4046 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4047 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4048
4049 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4050 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4051 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4052 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4053 else
4054 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4055
4056 style = GetWindowLongA(hwnd, GWL_STYLE);
4057 if (set) ok(style & set, "style %08x should be set\n", set);
4058 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4059
4060 /* a subsequent call should do nothing */
4061 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4062 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4063 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4064
4065 xmin = 0xdeadbeef;
4066 xmax = 0xdeadbeef;
4067 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4068 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4069 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4070 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4071 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4072 }
4073
4074 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4075 {
4076 DWORD style, exstyle;
4077 SCROLLINFO si;
4078 BOOL ret;
4079
4080 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4081 style = GetWindowLongA(hwnd, GWL_STYLE);
4082 /* do not be confused by WS_DLGFRAME set */
4083 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4084
4085 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4086 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4087
4088 si.cbSize = sizeof(si);
4089 si.fMask = SIF_RANGE;
4090 si.nMin = min;
4091 si.nMax = max;
4092 SetScrollInfo(hwnd, ctl, &si, TRUE);
4093 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4094 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4095 else
4096 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4097
4098 style = GetWindowLongA(hwnd, GWL_STYLE);
4099 if (set) ok(style & set, "style %08x should be set\n", set);
4100 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4101
4102 /* a subsequent call should do nothing */
4103 SetScrollInfo(hwnd, ctl, &si, TRUE);
4104 if (style & WS_HSCROLL)
4105 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4106 else if (style & WS_VSCROLL)
4107 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4108 else
4109 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4110
4111 si.fMask = SIF_PAGE;
4112 si.nPage = 5;
4113 SetScrollInfo(hwnd, ctl, &si, FALSE);
4114 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4115
4116 si.fMask = SIF_POS;
4117 si.nPos = max - 1;
4118 SetScrollInfo(hwnd, ctl, &si, FALSE);
4119 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4120
4121 si.fMask = SIF_RANGE;
4122 si.nMin = 0xdeadbeef;
4123 si.nMax = 0xdeadbeef;
4124 ret = GetScrollInfo(hwnd, ctl, &si);
4125 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4126 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4127 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4128 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4129 }
4130
4131 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4132 static void test_scroll_messages(HWND hwnd)
4133 {
4134 SCROLLINFO si;
4135 INT min, max;
4136 BOOL ret;
4137
4138 flush_events();
4139 flush_sequence();
4140
4141 min = 0xdeadbeef;
4142 max = 0xdeadbeef;
4143 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4144 ok( ret, "GetScrollRange error %d\n", GetLastError());
4145 if (sequence->message != WmGetScrollRangeSeq[0].message)
4146 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4147 /* values of min and max are undefined */
4148 flush_sequence();
4149
4150 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4151 ok( ret, "SetScrollRange error %d\n", GetLastError());
4152 if (sequence->message != WmSetScrollRangeSeq[0].message)
4153 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4154 flush_sequence();
4155
4156 min = 0xdeadbeef;
4157 max = 0xdeadbeef;
4158 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4159 ok( ret, "GetScrollRange error %d\n", GetLastError());
4160 if (sequence->message != WmGetScrollRangeSeq[0].message)
4161 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4162 /* values of min and max are undefined */
4163 flush_sequence();
4164
4165 si.cbSize = sizeof(si);
4166 si.fMask = SIF_RANGE;
4167 si.nMin = 20;
4168 si.nMax = 160;
4169 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4170 if (sequence->message != WmSetScrollRangeSeq[0].message)
4171 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4172 flush_sequence();
4173
4174 si.fMask = SIF_PAGE;
4175 si.nPage = 10;
4176 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4177 if (sequence->message != WmSetScrollRangeSeq[0].message)
4178 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4179 flush_sequence();
4180
4181 si.fMask = SIF_POS;
4182 si.nPos = 20;
4183 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4184 if (sequence->message != WmSetScrollRangeSeq[0].message)
4185 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4186 flush_sequence();
4187
4188 si.fMask = SIF_RANGE;
4189 si.nMin = 0xdeadbeef;
4190 si.nMax = 0xdeadbeef;
4191 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4192 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4193 if (sequence->message != WmGetScrollInfoSeq[0].message)
4194 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4195 /* values of min and max are undefined */
4196 flush_sequence();
4197
4198 /* set WS_HSCROLL */
4199 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4200 /* clear WS_HSCROLL */
4201 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4202
4203 /* set WS_HSCROLL */
4204 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4205 /* clear WS_HSCROLL */
4206 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4207
4208 /* set WS_VSCROLL */
4209 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4210 /* clear WS_VSCROLL */
4211 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4212
4213 /* set WS_VSCROLL */
4214 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4215 /* clear WS_VSCROLL */
4216 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4217 }
4218
4219 static void test_showwindow(void)
4220 {
4221 HWND hwnd, hchild;
4222 RECT rc;
4223
4224 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4225 100, 100, 200, 200, 0, 0, 0, NULL);
4226 ok (hwnd != 0, "Failed to create overlapped window\n");
4227 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4228 0, 0, 10, 10, hwnd, 0, 0, NULL);
4229 ok (hchild != 0, "Failed to create child\n");
4230 flush_sequence();
4231
4232 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4233 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4234 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4235 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4236
4237 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4238 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4239 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4240 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4241 /* back to invisible */
4242 ShowWindow(hchild, SW_HIDE);
4243 ShowWindow(hwnd, SW_HIDE);
4244 flush_sequence();
4245 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4246 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4247 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4248 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4249 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4250 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4251 flush_sequence();
4252 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4253 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4254 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4255 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4256 ShowWindow( hwnd, SW_SHOW);
4257 flush_sequence();
4258 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4259 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4260 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4261
4262 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4263 ShowWindow( hchild, SW_HIDE);
4264 flush_sequence();
4265 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4266 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4267 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4268
4269 SetCapture(hchild);
4270 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4271 DestroyWindow(hchild);
4272 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4273
4274 DestroyWindow(hwnd);
4275 flush_sequence();
4276
4277 /* Popup windows */
4278 /* Test 1:
4279 * 1. Create invisible maximized popup window.
4280 * 2. Move and resize it.
4281 * 3. Show it maximized.
4282 */
4283 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4284 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4285 100, 100, 200, 200, 0, 0, 0, NULL);
4286 ok (hwnd != 0, "Failed to create popup window\n");
4287 ok(IsZoomed(hwnd), "window should be maximized\n");
4288 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4289
4290 GetWindowRect(hwnd, &rc);
4291 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4292 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4293 "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4294 rc.left, rc.top, rc.right, rc.bottom);
4295 /* Reset window's size & position */
4296 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4297 ok(IsZoomed(hwnd), "window should be maximized\n");
4298 flush_sequence();
4299
4300 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4301 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4302 ok(IsZoomed(hwnd), "window should be maximized\n");
4303 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4304
4305 GetWindowRect(hwnd, &rc);
4306 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4307 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4308 "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4309 rc.left, rc.top, rc.right, rc.bottom);
4310 DestroyWindow(hwnd);
4311 flush_sequence();
4312
4313 /* Test 2:
4314 * 1. Create invisible maximized popup window.
4315 * 2. Show it maximized.
4316 */
4317 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4318 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4319 100, 100, 200, 200, 0, 0, 0, NULL);
4320 ok (hwnd != 0, "Failed to create popup window\n");
4321 ok(IsZoomed(hwnd), "window should be maximized\n");
4322 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4323
4324 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4325 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4326 ok(IsZoomed(hwnd), "window should be maximized\n");
4327 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4328 DestroyWindow(hwnd);
4329 flush_sequence();
4330
4331 /* Test 3:
4332 * 1. Create visible maximized popup window.
4333 */
4334 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4335 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4336 100, 100, 200, 200, 0, 0, 0, NULL);
4337 ok (hwnd != 0, "Failed to create popup window\n");
4338 ok(IsZoomed(hwnd), "window should be maximized\n");
4339 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4340 DestroyWindow(hwnd);
4341 flush_sequence();
4342
4343 /* Test 4:
4344 * 1. Create visible popup window.
4345 * 2. Maximize it.
4346 */
4347 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4348 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4349 100, 100, 200, 200, 0, 0, 0, NULL);
4350 ok (hwnd != 0, "Failed to create popup window\n");
4351 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4352 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4353
4354 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4355 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4356 ok(IsZoomed(hwnd), "window should be maximized\n");
4357 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4358 DestroyWindow(hwnd);
4359 flush_sequence();
4360 }
4361
4362 static void test_sys_menu(void)
4363 {
4364 HWND hwnd;
4365 HMENU hmenu;
4366 UINT state;
4367
4368 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4369 100, 100, 200, 200, 0, 0, 0, NULL);
4370 ok (hwnd != 0, "Failed to create overlapped window\n");
4371
4372 flush_sequence();
4373
4374 /* test existing window without CS_NOCLOSE style */
4375 hmenu = GetSystemMenu(hwnd, FALSE);
4376 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4377
4378 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4379 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4380 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4381
4382 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4383 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4384
4385 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4386 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4387 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4388
4389 EnableMenuItem(hmenu, SC_CLOSE, 0);
4390 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4391
4392 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4393 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4394 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4395
4396 /* test whether removing WS_SYSMENU destroys a system menu */
4397 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4398 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4399 flush_sequence();
4400 hmenu = GetSystemMenu(hwnd, FALSE);
4401 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4402
4403 DestroyWindow(hwnd);
4404
4405 /* test new window with CS_NOCLOSE style */
4406 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4407 100, 100, 200, 200, 0, 0, 0, NULL);
4408 ok (hwnd != 0, "Failed to create overlapped window\n");
4409
4410 hmenu = GetSystemMenu(hwnd, FALSE);
4411 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4412
4413 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4414 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4415
4416 DestroyWindow(hwnd);
4417
4418 /* test new window without WS_SYSMENU style */
4419 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4420 100, 100, 200, 200, 0, 0, 0, NULL);
4421 ok(hwnd != 0, "Failed to create overlapped window\n");
4422
4423 hmenu = GetSystemMenu(hwnd, FALSE);
4424 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4425
4426 DestroyWindow(hwnd);
4427 }
4428
4429 /* For shown WS_OVERLAPPEDWINDOW */
4430 static const struct message WmSetIcon_1[] = {
4431 { WM_SETICON, sent },
4432 { 0x00AE, sent|defwinproc|optional }, /* XP */
4433 { WM_GETTEXT, sent|defwinproc|optional },
4434 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4435 { 0 }
4436 };
4437
4438 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4439 static const struct message WmSetIcon_2[] = {
4440 { WM_SETICON, sent },
4441 { 0 }
4442 };
4443
4444 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4445 static const struct message WmInitEndSession[] = {
4446 { 0x003B, sent },
4447 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4448 { 0 }
4449 };
4450
4451 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4452 static const struct message WmInitEndSession_2[] = {
4453 { 0x003B, sent },
4454 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4455 { 0 }
4456 };
4457
4458 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4459 static const struct message WmInitEndSession_3[] = {
4460 { 0x003B, sent },
4461 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4462 { 0 }
4463 };
4464
4465 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4466 static const struct message WmInitEndSession_4[] = {
4467 { 0x003B, sent },
4468 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4469 { 0 }
4470 };
4471
4472 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4473 static const struct message WmInitEndSession_5[] = {
4474 { 0x003B, sent },
4475 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4476 { 0 }
4477 };
4478
4479 static const struct message WmOptionalPaint[] = {
4480 { WM_PAINT, sent|optional },
4481 { WM_NCPAINT, sent|beginpaint|optional },
4482 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4483 { WM_ERASEBKGND, sent|beginpaint|optional },
4484 { 0 }
4485 };
4486
4487 static const struct message WmZOrder[] = {
4488 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4489 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4490 { HCBT_ACTIVATE, hook },
4491 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4492 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4493 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4494 { WM_GETTEXT, sent|optional },
4495 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4496 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4497 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4498 { WM_GETTEXT, sent|defwinproc|optional },
4499 { WM_GETTEXT, sent|defwinproc|optional },
4500 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4501 { HCBT_SETFOCUS, hook },
4502 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4503 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4504 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4505 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4506 { WM_GETTEXT, sent|optional },
4507 { WM_NCCALCSIZE, sent|optional },
4508 { 0 }
4509 };
4510
4511 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4512 {
4513 DWORD ret;
4514 MSG msg;
4515
4516 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4517 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4518
4519 PostMessageA(hwnd, WM_USER, 0, 0);
4520
4521 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4522 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4523
4524 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4525 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4526
4527 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4528 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4529
4530 PostMessageA(hwnd, WM_USER, 0, 0);
4531
4532 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4533 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4534
4535 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4536 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4537
4538 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4539 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4540 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4541
4542 PostMessageA(hwnd, WM_USER, 0, 0);
4543
4544 /* new incoming message causes it to become signaled again */
4545 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4546 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4547
4548 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4549 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4550 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4551 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4552 }
4553
4554 /* test if we receive the right sequence of messages */
4555 static void test_messages(void)
4556 {
4557 HWND hwnd, hparent, hchild;
4558 HWND hchild2, hbutton;
4559 HMENU hmenu;
4560 MSG msg;
4561 LRESULT res;
4562 POINT pos;
4563
4564 flush_sequence();
4565
4566 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4567 100, 100, 200, 200, 0, 0, 0, NULL);
4568 ok (hwnd != 0, "Failed to create overlapped window\n");
4569 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4570
4571 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4572 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4573 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4574
4575 /* test WM_SETREDRAW on a not visible top level window */
4576 test_WM_SETREDRAW(hwnd);
4577
4578 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4579 flush_events();
4580 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4581 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4582
4583 ok(GetActiveWindow() == hwnd, "window should be active\n");
4584 ok(GetFocus() == hwnd, "window should have input focus\n");
4585 ShowWindow(hwnd, SW_HIDE);
4586 flush_events();
4587 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4588
4589 ShowWindow(hwnd, SW_SHOW);
4590 flush_events();
4591 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4592
4593 ShowWindow(hwnd, SW_HIDE);
4594 flush_events();
4595 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4596
4597 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4598 flush_events();
4599 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4600 flush_sequence();
4601
4602 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4603 {
4604 ShowWindow(hwnd, SW_RESTORE);
4605 flush_events();
4606 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4607 flush_sequence();
4608 }
4609
4610 ShowWindow(hwnd, SW_MINIMIZE);
4611 flush_events();
4612 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4613 flush_sequence();
4614
4615 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4616 {
4617 ShowWindow(hwnd, SW_RESTORE);
4618 flush_events();
4619 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4620 flush_sequence();
4621 }
4622
4623 ShowWindow(hwnd, SW_SHOW);
4624 flush_events();
4625 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4626
4627 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4628 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4629 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4630 ok(GetActiveWindow() == hwnd, "window should still be active\n");
4631
4632 /* test WM_SETREDRAW on a visible top level window */
4633 ShowWindow(hwnd, SW_SHOW);
4634 flush_events();
4635 test_WM_SETREDRAW(hwnd);
4636
4637 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4638 test_scroll_messages(hwnd);
4639
4640 /* test resizing and moving */
4641 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4642 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4643 flush_events();
4644 flush_sequence();
4645 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4646 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4647 flush_events();
4648 flush_sequence();
4649 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4650 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4651 flush_events();
4652 flush_sequence();
4653
4654 /* popups don't get WM_GETMINMAXINFO */
4655 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4656 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4657 flush_sequence();
4658 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4659 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4660
4661 DestroyWindow(hwnd);
4662 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4663
4664 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4665 100, 100, 200, 200, 0, 0, 0, NULL);
4666 ok (hparent != 0, "Failed to create parent window\n");
4667 flush_sequence();
4668
4669 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4670 0, 0, 10, 10, hparent, 0, 0, NULL);
4671 ok (hchild != 0, "Failed to create child window\n");
4672 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4673 DestroyWindow(hchild);
4674 flush_sequence();
4675
4676 /* visible child window with a caption */
4677 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4678 WS_CHILD | WS_VISIBLE | WS_CAPTION,
4679 0, 0, 10, 10, hparent, 0, 0, NULL);
4680 ok (hchild != 0, "Failed to create child window\n");
4681 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4682
4683 trace("testing scroll APIs on a visible child window %p\n", hchild);
4684 test_scroll_messages(hchild);
4685
4686 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4687 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4688
4689 DestroyWindow(hchild);
4690 flush_sequence();
4691
4692 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4693 0, 0, 10, 10, hparent, 0, 0, NULL);
4694 ok (hchild != 0, "Failed to create child window\n");
4695 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4696
4697 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4698 100, 100, 50, 50, hparent, 0, 0, NULL);
4699 ok (hchild2 != 0, "Failed to create child2 window\n");
4700 flush_sequence();
4701
4702 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4703 0, 100, 50, 50, hchild, 0, 0, NULL);
4704 ok (hbutton != 0, "Failed to create button window\n");
4705
4706 /* test WM_SETREDRAW on a not visible child window */
4707 test_WM_SETREDRAW(hchild);
4708
4709 ShowWindow(hchild, SW_SHOW);
4710 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4711
4712 /* check parent messages too */
4713 log_all_parent_messages++;
4714 ShowWindow(hchild, SW_HIDE);
4715 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4716 log_all_parent_messages--;
4717
4718 ShowWindow(hchild, SW_SHOW);
4719 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4720
4721 ShowWindow(hchild, SW_HIDE);
4722 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4723
4724 ShowWindow(hchild, SW_SHOW);
4725 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4726
4727 /* test WM_SETREDRAW on a visible child window */
4728 test_WM_SETREDRAW(hchild);
4729
4730 log_all_parent_messages++;
4731 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4732 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4733 log_all_parent_messages--;
4734
4735 ShowWindow(hchild, SW_HIDE);
4736 flush_sequence();
4737 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4738 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4739
4740 ShowWindow(hchild, SW_HIDE);
4741 flush_sequence();
4742 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4743 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4744
4745 /* DestroyWindow sequence below expects that a child has focus */
4746 SetFocus(hchild);
4747 flush_sequence();
4748
4749 DestroyWindow(hchild);
4750 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4751 DestroyWindow(hchild2);
4752 DestroyWindow(hbutton);
4753
4754 flush_sequence();
4755 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4756 0, 0, 100, 100, hparent, 0, 0, NULL);
4757 ok (hchild != 0, "Failed to create child popup window\n");
4758 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4759 DestroyWindow(hchild);
4760
4761 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4762 flush_sequence();
4763 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4764 0, 0, 100, 100, hparent, 0, 0, NULL);
4765 ok (hchild != 0, "Failed to create popup window\n");
4766 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4767 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4768 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4769 flush_sequence();
4770 ShowWindow(hchild, SW_SHOW);
4771 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4772 flush_sequence();
4773 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4774 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4775 flush_sequence();
4776 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4777 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4778 DestroyWindow(hchild);
4779
4780 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4781 * changes nothing in message sequences.
4782 */
4783 flush_sequence();
4784 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4785 0, 0, 100, 100, hparent, 0, 0, NULL);
4786 ok (hchild != 0, "Failed to create popup window\n");
4787 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4788 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4789 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4790 flush_sequence();
4791 ShowWindow(hchild, SW_SHOW);
4792 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4793 flush_sequence();
4794 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4795 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4796 DestroyWindow(hchild);
4797
4798 flush_sequence();
4799 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4800 0, 0, 100, 100, hparent, 0, 0, NULL);
4801 ok(hwnd != 0, "Failed to create custom dialog window\n");
4802 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4803
4804 if(0) {
4805 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4806 test_scroll_messages(hwnd);
4807 }
4808
4809 flush_sequence();
4810
4811 test_def_id = TRUE;
4812 SendMessageA(hwnd, WM_NULL, 0, 0);
4813
4814 flush_sequence();
4815 after_end_dialog = TRUE;
4816 EndDialog( hwnd, 0 );
4817 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4818
4819 DestroyWindow(hwnd);
4820 after_end_dialog = FALSE;
4821 test_def_id = FALSE;
4822
4823 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
4824 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
4825
4826 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
4827 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4828 ok(hwnd != 0, "Failed to create custom dialog window\n");
4829 flush_sequence();
4830 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4831 ShowWindow(hwnd, SW_SHOW);
4832 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4833
4834 flush_events();
4835 flush_sequence();
4836 ok(DrawMenuBar(hwnd), "DrawMenuBar failed: %d\n", GetLastError());
4837 flush_events();
4838 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4839 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
4840 DestroyWindow(hwnd);
4841
4842 flush_sequence();
4843 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4844 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4845
4846 DestroyWindow(hparent);
4847 flush_sequence();
4848
4849 /* Message sequence for SetMenu */
4850 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
4851 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
4852 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4853
4854 hmenu = CreateMenu();
4855 ok (hmenu != 0, "Failed to create menu\n");
4856 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4857 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4858 100, 100, 200, 200, 0, hmenu, 0, NULL);
4859 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4860 ok (SetMenu(hwnd, 0), "SetMenu\n");
4861 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4862 ok (SetMenu(hwnd, 0), "SetMenu\n");
4863 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4864 ShowWindow(hwnd, SW_SHOW);
4865 UpdateWindow( hwnd );
4866 flush_events();
4867 flush_sequence();
4868 ok (SetMenu(hwnd, 0), "SetMenu\n");
4869 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4870 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4871 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4872
4873 UpdateWindow( hwnd );
4874 flush_events();
4875 flush_sequence();
4876 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4877 flush_events();
4878 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4879
4880 DestroyWindow(hwnd);
4881 flush_sequence();
4882
4883 /* Message sequence for EnableWindow */
4884 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4885 100, 100, 200, 200, 0, 0, 0, NULL);
4886 ok (hparent != 0, "Failed to create parent window\n");
4887 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4888 0, 0, 10, 10, hparent, 0, 0, NULL);
4889 ok (hchild != 0, "Failed to create child window\n");
4890
4891 SetFocus(hchild);
4892 flush_events();
4893 flush_sequence();
4894
4895 EnableWindow(hparent, FALSE);
4896 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4897
4898 EnableWindow(hparent, TRUE);
4899 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4900
4901 flush_events();
4902 flush_sequence();
4903
4904 test_MsgWaitForMultipleObjects(hparent);
4905
4906 /* the following test causes an exception in user.exe under win9x */
4907 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4908 {
4909 DestroyWindow(hparent);
4910 flush_sequence();
4911 return;
4912 }
4913 PostMessageW( hparent, WM_USER+1, 0, 0 );
4914 /* PeekMessage(NULL) fails, but still removes the message */
4915 SetLastError(0xdeadbeef);
4916 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4917 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4918 GetLastError() == 0xdeadbeef, /* NT4 */
4919 "last error is %d\n", GetLastError() );
4920 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4921 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4922
4923 DestroyWindow(hchild);
4924 DestroyWindow(hparent);
4925 flush_sequence();
4926
4927 /* Message sequences for WM_SETICON */
4928 trace("testing WM_SETICON\n");
4929 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4930 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4931 NULL, NULL, 0);
4932 ShowWindow(hwnd, SW_SHOW);
4933 UpdateWindow(hwnd);
4934 flush_events();
4935 flush_sequence();
4936 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4937 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4938
4939 ShowWindow(hwnd, SW_HIDE);
4940 flush_events();
4941 flush_sequence();
4942 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4943 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4944 DestroyWindow(hwnd);
4945 flush_sequence();
4946
4947 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4948 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4949 NULL, NULL, 0);
4950 ShowWindow(hwnd, SW_SHOW);
4951 UpdateWindow(hwnd);
4952 flush_events();
4953 flush_sequence();
4954 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4955 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4956
4957 ShowWindow(hwnd, SW_HIDE);
4958 flush_events();
4959 flush_sequence();
4960 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4961 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4962
4963 flush_sequence();
4964 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
4965 if (!res)
4966 {
4967 todo_wine win_skip( "Message 0x3b not supported\n" );
4968 goto done;
4969 }
4970 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4971 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4972 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
4973 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4974 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4975 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
4976 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4977 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4978
4979 flush_sequence();
4980 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
4981 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4982 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4983 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
4984 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4985 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4986
4987 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
4988 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4989 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4990
4991 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
4992 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4993 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4994
4995 done:
4996 DestroyWindow(hwnd);
4997 flush_sequence();
4998 }
4999
5000 static void test_setwindowpos(void)
5001 {
5002 HWND hwnd;
5003 RECT rc;
5004 LRESULT res;
5005 const INT winX = 100;
5006 const INT winY = 100;
5007 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5008
5009 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5010 0, 0, winX, winY, 0,
5011 NULL, NULL, 0);
5012
5013 GetWindowRect(hwnd, &rc);
5014 expect(sysX, rc.right);
5015 expect(winY, rc.bottom);
5016
5017 flush_events();
5018 flush_sequence();
5019 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5020 ok_sequence(WmZOrder, "Z-Order", TRUE);
5021 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5022
5023 GetWindowRect(hwnd, &rc);
5024 expect(sysX, rc.right);
5025 expect(winY, rc.bottom);
5026 DestroyWindow(hwnd);
5027 }
5028
5029 static void invisible_parent_tests(void)
5030 {
5031 HWND hparent, hchild;
5032
5033 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5034 100, 100, 200, 200, 0, 0, 0, NULL);
5035 ok (hparent != 0, "Failed to create parent window\n");
5036 flush_sequence();
5037
5038 /* test showing child with hidden parent */
5039
5040 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5041 0, 0, 10, 10, hparent, 0, 0, NULL);
5042 ok (hchild != 0, "Failed to create child window\n");
5043 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5044
5045 ShowWindow( hchild, SW_MINIMIZE );
5046 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5047 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5048 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5049
5050 /* repeat */
5051 flush_events();
5052 flush_sequence();
5053 ShowWindow( hchild, SW_MINIMIZE );
5054 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5055
5056 DestroyWindow(hchild);
5057 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5058 0, 0, 10, 10, hparent, 0, 0, NULL);
5059 flush_sequence();
5060
5061 ShowWindow( hchild, SW_MAXIMIZE );
5062 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5063 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5064 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5065
5066 /* repeat */
5067 flush_events();
5068 flush_sequence();
5069 ShowWindow( hchild, SW_MAXIMIZE );
5070 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5071
5072 DestroyWindow(hchild);
5073 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5074 0, 0, 10, 10, hparent, 0, 0, NULL);
5075 flush_sequence();
5076
5077 ShowWindow( hchild, SW_RESTORE );
5078 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5079 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5080 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5081
5082 DestroyWindow(hchild);
5083 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5084 0, 0, 10, 10, hparent, 0, 0, NULL);
5085 flush_sequence();
5086
5087 ShowWindow( hchild, SW_SHOWMINIMIZED );
5088 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5089 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5090 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5091
5092 /* repeat */
5093 flush_events();
5094 flush_sequence();
5095 ShowWindow( hchild, SW_SHOWMINIMIZED );
5096 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5097
5098 DestroyWindow(hchild);
5099 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5100 0, 0, 10, 10, hparent, 0, 0, NULL);
5101 flush_sequence();
5102
5103 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5104 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5105 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5106 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5107 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5108
5109 DestroyWindow(hchild);
5110 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5111 0, 0, 10, 10, hparent, 0, 0, NULL);
5112 flush_sequence();
5113
5114 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5115 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5116 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5117 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5118
5119 /* repeat */
5120 flush_events();
5121 flush_sequence();
5122 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5123 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5124
5125 DestroyWindow(hchild);
5126 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5127 0, 0, 10, 10, hparent, 0, 0, NULL);
5128 flush_sequence();
5129
5130 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5131 ShowWindow( hchild, SW_FORCEMINIMIZE );
5132 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5133 todo_wine {
5134 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5135 }
5136 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5137
5138 DestroyWindow(hchild);
5139 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5140 0, 0, 10, 10, hparent, 0, 0, NULL);
5141 flush_sequence();
5142
5143 ShowWindow( hchild, SW_SHOWNA );
5144 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5145 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5146 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5147
5148 /* repeat */
5149 flush_events();
5150 flush_sequence();
5151 ShowWindow( hchild, SW_SHOWNA );
5152 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5153
5154 DestroyWindow(hchild);
5155 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5156 0, 0, 10, 10, hparent, 0, 0, NULL);
5157 flush_sequence();
5158
5159 ShowWindow( hchild, SW_SHOW );
5160 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5161 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5162 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5163
5164 /* repeat */
5165 flush_events();
5166 flush_sequence();
5167 ShowWindow( hchild, SW_SHOW );
5168 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5169
5170 ShowWindow( hchild, SW_HIDE );
5171 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5172 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5173 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5174
5175 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5176 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5177 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5178 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5179
5180 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5181 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5182 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5183 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5184
5185 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5186 flush_sequence();
5187 DestroyWindow(hchild);
5188 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5189
5190 DestroyWindow(hparent);
5191 flush_sequence();
5192 }
5193
5194 /****************** button message test *************************/
5195 #define ID_BUTTON 0x000e
5196
5197 static const struct message WmSetFocusButtonSeq[] =
5198 {
5199 { HCBT_SETFOCUS, hook },
5200 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5201 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5202 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5203 { WM_SETFOCUS, sent|wparam, 0 },
5204 { WM_CTLCOLORBTN, sent|parent },
5205 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5206 { WM_APP, sent|wparam|lparam, 0, 0 },
5207 { 0 }
5208 };
5209 static const struct message WmKillFocusButtonSeq[] =
5210 {
5211 { HCBT_SETFOCUS, hook },
5212 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5213 { WM_KILLFOCUS, sent|wparam, 0 },
5214 { WM_CTLCOLORBTN, sent|parent },
5215 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5216 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5217 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5218 { WM_APP, sent|wparam|lparam, 0, 0 },
5219 { WM_PAINT, sent },
5220 { WM_CTLCOLORBTN, sent|parent },
5221 { 0 }
5222 };
5223 static const struct message WmSetFocusStaticSeq[] =
5224 {
5225 { HCBT_SETFOCUS, hook },
5226 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5227 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5228 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5229 { WM_SETFOCUS, sent|wparam, 0 },
5230 { WM_CTLCOLORSTATIC, sent|parent },
5231 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5232 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5233 { WM_APP, sent|wparam|lparam, 0, 0 },
5234 { 0 }
5235 };
5236 static const struct message WmKillFocusStaticSeq[] =
5237 {
5238 { HCBT_SETFOCUS, hook },
5239 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5240 { WM_KILLFOCUS, sent|wparam, 0 },
5241 { WM_CTLCOLORSTATIC, sent|parent },
5242 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5243 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5244 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5245 { WM_APP, sent|wparam|lparam, 0, 0 },
5246 { WM_PAINT, sent },
5247 { WM_CTLCOLORSTATIC, sent|parent },
5248 { 0 }
5249 };
5250 static const struct message WmSetFocusOwnerdrawSeq[] =
5251 {
5252 { HCBT_SETFOCUS, hook },
5253 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5254 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5255 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5256 { WM_SETFOCUS, sent|wparam, 0 },
5257 { WM_CTLCOLORBTN, sent|parent },
5258 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5259 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5260 { WM_APP, sent|wparam|lparam, 0, 0 },
5261 { 0 }
5262 };
5263 static const struct message WmKillFocusOwnerdrawSeq[] =
5264 {
5265 { HCBT_SETFOCUS, hook },
5266 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5267 { WM_KILLFOCUS, sent|wparam, 0 },
5268 { WM_CTLCOLORBTN, sent|parent },
5269 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5270 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5271 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5272 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5273 { WM_APP, sent|wparam|lparam, 0, 0 },
5274 { WM_PAINT, sent },
5275 { WM_CTLCOLORBTN, sent|parent },
5276 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5277 { 0 }
5278 };
5279 static const struct message WmLButtonDownSeq[] =
5280 {
5281 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5282 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5283 { HCBT_SETFOCUS, hook },
5284 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5285 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5286 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5287 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5288 { WM_CTLCOLORBTN, sent|defwinproc },
5289 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5290 { WM_CTLCOLORBTN, sent|defwinproc },
5291 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5292 { 0 }
5293 };
5294 static const struct message WmLButtonUpSeq[] =
5295 {
5296 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5297 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5298 { WM_CTLCOLORBTN, sent|defwinproc },
5299 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5300 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5301 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5302 { 0 }
5303 };
5304 static const struct message WmSetFontButtonSeq[] =
5305 {
5306 { WM_SETFONT, sent },
5307 { WM_PAINT, sent },
5308 { WM_ERASEBKGND, sent|defwinproc|optional },
5309 { WM_CTLCOLORBTN, sent|defwinproc },
5310 { 0 }
5311 };
5312 static const struct message WmSetStyleButtonSeq[] =
5313 {
5314 { BM_SETSTYLE, sent },
5315 { WM_APP, sent|wparam|lparam, 0, 0 },
5316 { WM_PAINT, sent },
5317 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5318 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5319 { WM_CTLCOLORBTN, sent|parent },
5320 { 0 }
5321 };
5322 static const struct message WmSetStyleStaticSeq[] =
5323 {
5324 { BM_SETSTYLE, sent },
5325 { WM_APP, sent|wparam|lparam, 0, 0 },
5326 { WM_PAINT, sent },
5327 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5328 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5329 { WM_CTLCOLORSTATIC, sent|parent },
5330 { 0 }
5331 };
5332 static const struct message WmSetStyleUserSeq[] =
5333 {
5334 { BM_SETSTYLE, sent },
5335 { WM_APP, sent|wparam|lparam, 0, 0 },
5336 { WM_PAINT, sent },
5337 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5338 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5339 { WM_CTLCOLORBTN, sent|parent },
5340 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5341 { 0 }
5342 };
5343 static const struct message WmSetStyleOwnerdrawSeq[] =
5344 {
5345 { BM_SETSTYLE, sent },
5346 { WM_APP, sent|wparam|lparam, 0, 0 },
5347 { WM_PAINT, sent },
5348 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5349 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5350 { WM_CTLCOLORBTN, sent|parent },
5351 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5352 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5353 { 0 }
5354 };
5355 static const struct message WmSetStateButtonSeq[] =
5356 {
5357 { BM_SETSTATE, sent },
5358 { WM_CTLCOLORBTN, sent|parent },
5359 { WM_APP, sent|wparam|lparam, 0, 0 },
5360 { 0 }
5361 };
5362 static const struct message WmSetStateStaticSeq[] =
5363 {
5364 { BM_SETSTATE, sent },
5365 { WM_CTLCOLORSTATIC, sent|parent },
5366 { WM_APP, sent|wparam|lparam, 0, 0 },
5367 { 0 }
5368 };
5369 static const struct message WmSetStateUserSeq[] =
5370 {
5371 { BM_SETSTATE, sent },
5372 { WM_CTLCOLORBTN, sent|parent },
5373 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
5374 { WM_APP, sent|wparam|lparam, 0, 0 },
5375 { 0 }
5376 };
5377 static const struct message WmSetStateOwnerdrawSeq[] =
5378 {
5379 { BM_SETSTATE, sent },
5380 { WM_CTLCOLORBTN, sent|parent },
5381 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
5382 { WM_APP, sent|wparam|lparam, 0, 0 },
5383 { 0 }
5384 };
5385 static const struct message WmClearStateButtonSeq[] =
5386 {
5387 { BM_SETSTATE, sent },
5388 { WM_CTLCOLORBTN, sent|parent },
5389 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
5390 { WM_APP, sent|wparam|lparam, 0, 0 },
5391 { 0 }
5392 };
5393 static const struct message WmClearStateOwnerdrawSeq[] =
5394 {
5395 { BM_SETSTATE, sent },
5396 { WM_CTLCOLORBTN, sent|parent },
5397 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
5398 { WM_APP, sent|wparam|lparam, 0, 0 },
5399 { 0 }
5400 };
5401 static const struct message WmSetCheckIgnoredSeq[] =
5402 {
5403 { BM_SETCHECK, sent },
5404 { WM_APP, sent|wparam|lparam, 0, 0 },
5405 { 0 }
5406 };
5407 static const struct message WmSetCheckStaticSeq[] =
5408 {
5409 { BM_SETCHECK, sent },
5410 { WM_CTLCOLORSTATIC, sent|parent },
5411 { WM_APP, sent|wparam|lparam, 0, 0 },
5412 { 0 }
5413 };
5414
5415 static WNDPROC old_button_proc;
5416
5417 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5418 {
5419 static LONG defwndproc_counter = 0;
5420 LRESULT ret;
5421 struct recvd_message msg;
5422
5423 if (ignore_message( message )) return 0;
5424
5425 switch (message)
5426 {
5427 case WM_SYNCPAINT:
5428 break;
5429 case BM_SETSTATE:
5430 if (GetCapture())
5431 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5432 /* fall through */
5433 default:
5434 msg.hwnd = hwnd;
5435 msg.message = message;
5436 msg.flags = sent|wparam|lparam;
5437 if (defwndproc_counter) msg.flags |= defwinproc;
5438 msg.wParam = wParam;
5439 msg.lParam = lParam;
5440 msg.descr = "button";
5441 add_message(&msg);
5442 }
5443
5444 defwndproc_counter++;
5445 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5446 defwndproc_counter--;
5447
5448 return ret;
5449 }
5450
5451 static void subclass_button(void)
5452 {
5453 WNDCLASSA cls;
5454
5455 if (!GetClassInfoA(0, "button", &cls)) assert(0);
5456
5457 old_button_proc = cls.lpfnWndProc;
5458
5459 cls.hInstance = GetModuleHandleA(NULL);
5460 cls.lpfnWndProc = button_hook_proc;
5461 cls.lpszClassName = "my_button_class";
5462 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5463 if (!RegisterClassA(&cls)) assert(0);
5464 }
5465
5466 static void test_button_messages(void)
5467 {
5468 static const struct
5469 {
5470 DWORD style;
5471 DWORD dlg_code;
5472 const struct message *setfocus;
5473 const struct message *killfocus;
5474 const struct message *setstyle;
5475 const struct message *setstate;
5476 const struct message *clearstate;
5477 const struct message *setcheck;
5478 } button[] = {
5479 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5480 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5481 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5482 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5483 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5484 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5485 { BS_CHECKBOX, DLGC_BUTTON,
5486 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5487 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5488 { BS_AUTOCHECKBOX, DLGC_BUTTON,
5489 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5490 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5491 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5492 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5493 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5494 { BS_3STATE, DLGC_BUTTON,
5495 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5496 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5497 { BS_AUTO3STATE, DLGC_BUTTON,
5498 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5499 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5500 { BS_GROUPBOX, DLGC_STATIC,
5501 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5502 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
5503 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5504 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
5505 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
5506 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5507 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5508 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5509 { BS_OWNERDRAW, DLGC_BUTTON,
5510 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
5511 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
5512 };
5513 unsigned int i;
5514 HWND hwnd, parent;
5515 DWORD dlg_code;
5516 HFONT zfont;
5517
5518 /* selection with VK_SPACE should capture button window */
5519 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5520 0, 0, 50, 14, 0, 0, 0, NULL);
5521 ok(hwnd != 0, "Failed to create button window\n");
5522 ReleaseCapture();
5523 SetFocus(hwnd);
5524 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5525 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5526 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5527 DestroyWindow(hwnd);
5528
5529 subclass_button();
5530
5531 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5532 100, 100, 200, 200, 0, 0, 0, NULL);
5533 ok(parent != 0, "Failed to create parent window\n");
5534
5535 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5536 {
5537 MSG msg;
5538 DWORD style, state;
5539
5540 trace("button style %08x\n", button[i].style);
5541
5542 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5543 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5544 ok(hwnd != 0, "Failed to create button window\n");
5545
5546 style = GetWindowLongA(hwnd, GWL_STYLE);
5547 style &= ~(WS_CHILD | BS_NOTIFY);
5548 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5549 if (button[i].style == BS_USERBUTTON)
5550 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5551 else
5552 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5553
5554 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5555 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5556
5557 ShowWindow(hwnd, SW_SHOW);
5558 UpdateWindow(hwnd);
5559 SetFocus(0);
5560 flush_events();
5561 SetFocus(0);
5562 flush_sequence();
5563
5564 log_all_parent_messages++;
5565
5566 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5567 SetFocus(hwnd);
5568 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5569 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5570 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5571
5572 SetFocus(0);
5573 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5574 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5575 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5576
5577 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5578
5579 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5580 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5581 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5582 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5583
5584 style = GetWindowLongA(hwnd, GWL_STYLE);
5585 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5586 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5587 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5588
5589 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5590 ok(state == 0, "expected state 0, got %04x\n", state);
5591
5592 flush_sequence();
5593
5594 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
5595 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5596 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5597 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
5598
5599 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5600 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
5601
5602 style = GetWindowLongA(hwnd, GWL_STYLE);
5603 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5604 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5605
5606 flush_sequence();
5607
5608 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
5609 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5610 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5611 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
5612
5613 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5614 ok(state == 0, "expected state 0, got %04x\n", state);
5615
5616 style = GetWindowLongA(hwnd, GWL_STYLE);
5617 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5618 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5619
5620 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5621 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5622
5623 flush_sequence();
5624
5625 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
5626 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5627 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5628 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
5629
5630 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5631 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5632
5633 style = GetWindowLongA(hwnd, GWL_STYLE);
5634 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5635 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5636
5637 flush_sequence();
5638
5639 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
5640 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5641 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5642 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
5643
5644 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5645 if (button[i].style == BS_PUSHBUTTON ||
5646 button[i].style == BS_DEFPUSHBUTTON ||
5647 button[i].style == BS_GROUPBOX ||
5648 button[i].style == BS_USERBUTTON ||
5649 button[i].style == BS_OWNERDRAW)
5650 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
5651 else
5652 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
5653
5654 style = GetWindowLongA(hwnd, GWL_STYLE);
5655 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5656 if (button[i].style == BS_RADIOBUTTON ||
5657 button[i].style == BS_AUTORADIOBUTTON)
5658 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
5659 else
5660 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5661
5662 log_all_parent_messages--;
5663
5664 DestroyWindow(hwnd);
5665 }
5666
5667 DestroyWindow(parent);
5668
5669 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5670 0, 0, 50, 14, 0, 0, 0, NULL);
5671 ok(hwnd != 0, "Failed to create button window\n");
5672
5673 SetForegroundWindow(hwnd);
5674 flush_events();
5675
5676 SetActiveWindow(hwnd);
5677 SetFocus(0);
5678 flush_sequence();
5679
5680 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5681 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5682
5683 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5684 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5685
5686 flush_sequence();
5687 zfont = GetStockObject(SYSTEM_FONT);
5688 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5689 UpdateWindow(hwnd);
5690 ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5691
5692 DestroyWindow(hwnd);
5693 }
5694
5695 /****************** static message test *************************/
5696 static const struct message WmSetFontStaticSeq[] =
5697 {
5698 { WM_SETFONT, sent },
5699 { WM_PAINT, sent|defwinproc|optional },
5700 { WM_ERASEBKGND, sent|defwinproc|optional },
5701 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5702 { 0 }
5703 };
5704
5705 static WNDPROC old_static_proc;
5706
5707 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5708 {
5709 static LONG defwndproc_counter = 0;
5710 LRESULT ret;
5711 struct recvd_message msg;
5712
5713 if (ignore_message( message )) return 0;
5714
5715 msg.hwnd = hwnd;
5716 msg.message = message;
5717 msg.flags = sent|wparam|lparam;
5718 if (defwndproc_counter) msg.flags |= defwinproc;
5719 msg.wParam = wParam;
5720 msg.lParam = lParam;
5721 msg.descr = "static";
5722 add_message(&msg);
5723
5724 defwndproc_counter++;
5725 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5726 defwndproc_counter--;
5727
5728 return ret;
5729 }
5730
5731 static void subclass_static(void)
5732 {
5733 WNDCLASSA cls;
5734
5735 if (!GetClassInfoA(0, "static", &cls)) assert(0);
5736
5737 old_static_proc = cls.lpfnWndProc;
5738
5739 cls.hInstance = GetModuleHandleA(NULL);
5740 cls.lpfnWndProc = static_hook_proc;
5741 cls.lpszClassName = "my_static_class";
5742 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5743 if (!RegisterClassA(&cls)) assert(0);
5744 }
5745
5746 static void test_static_messages(void)
5747 {
5748 /* FIXME: make as comprehensive as the button message test */
5749 static const struct
5750 {
5751 DWORD style;
5752 DWORD dlg_code;
5753 const struct message *setfont;
5754 } static_ctrl[] = {
5755 { SS_LEFT, DLGC_STATIC,
5756 WmSetFontStaticSeq }
5757 };
5758 unsigned int i;
5759 HWND hwnd;
5760 DWORD dlg_code;
5761
5762 subclass_static();
5763
5764 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5765 {
5766 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5767 0, 0, 50, 14, 0, 0, 0, NULL);
5768 ok(hwnd != 0, "Failed to create static window\n");
5769
5770 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5771 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5772
5773 ShowWindow(hwnd, SW_SHOW);
5774 UpdateWindow(hwnd);
5775 SetFocus(0);
5776 flush_sequence();
5777
5778 trace("static style %08x\n", static_ctrl[i].style);
5779 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5780 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5781
5782 DestroyWindow(hwnd);
5783 }
5784 }
5785
5786 /****************** ComboBox message test *************************/
5787 #define ID_COMBOBOX 0x000f
5788
5789 static const struct message WmKeyDownComboSeq[] =
5790 {
5791 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5792 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5793 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5794 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5795 { WM_CTLCOLOREDIT, sent|parent },
5796 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5797 { 0 }
5798 };
5799
5800 static const struct message WmSetPosComboSeq[] =
5801 {
5802 { WM_WINDOWPOSCHANGING, sent },
5803 { WM_NCCALCSIZE, sent|wparam, TRUE },
5804 { WM_CHILDACTIVATE, sent },
5805 { WM_WINDOWPOSCHANGED, sent },
5806 { WM_MOVE, sent|defwinproc },
5807 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5808 { WM_WINDOWPOSCHANGING, sent|defwinproc },
5809 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
5810 { WM_WINDOWPOSCHANGED, sent|defwinproc },
5811 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5812 { 0 }
5813 };
5814
5815 static WNDPROC old_combobox_proc;
5816
5817 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5818 {
5819 static LONG defwndproc_counter = 0;
5820 LRESULT ret;
5821 struct recvd_message msg;
5822
5823 /* do not log painting messages */
5824 if (message != WM_PAINT &&
5825 message != WM_NCPAINT &&
5826 message != WM_SYNCPAINT &&
5827 message != WM_ERASEBKGND &&
5828 message != WM_NCHITTEST &&
5829 message != WM_GETTEXT &&
5830 !ignore_message( message ))
5831 {
5832 msg.hwnd = hwnd;
5833 msg.message = message;
5834 msg.flags = sent|wparam|lparam;
5835 if (defwndproc_counter) msg.flags |= defwinproc;
5836 msg.wParam = wParam;
5837 msg.lParam = lParam;
5838 msg.descr = "combo";
5839 add_message(&msg);
5840 }
5841
5842 defwndproc_counter++;
5843 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5844 defwndproc_counter--;
5845
5846 return ret;
5847 }
5848
5849 static void subclass_combobox(void)
5850 {
5851 WNDCLASSA cls;
5852
5853 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5854
5855 old_combobox_proc = cls.lpfnWndProc;
5856
5857 cls.hInstance = GetModuleHandleA(NULL);
5858 cls.lpfnWndProc = combobox_hook_proc;
5859 cls.lpszClassName = "my_combobox_class";
5860 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5861 if (!RegisterClassA(&cls)) assert(0);
5862 }
5863
5864 static void test_combobox_messages(void)
5865 {
5866 HWND parent, combo;
5867 LRESULT ret;
5868
5869 subclass_combobox();
5870
5871 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5872 100, 100, 200, 200, 0, 0, 0, NULL);
5873 ok(parent != 0, "Failed to create parent window\n");
5874 flush_sequence();
5875
5876 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5877 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5878 ok(combo != 0, "Failed to create combobox window\n");
5879
5880 UpdateWindow(combo);
5881
5882 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
5883 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5884
5885 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5886 ok(ret == 0, "expected 0, got %ld\n", ret);
5887 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5888 ok(ret == 1, "expected 1, got %ld\n", ret);
5889 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5890 ok(ret == 2, "expected 2, got %ld\n", ret);
5891
5892 SendMessageA(combo, CB_SETCURSEL, 0, 0);
5893 SetFocus(combo);
5894 flush_sequence();
5895
5896 log_all_parent_messages++;
5897 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
5898 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
5899 log_all_parent_messages--;
5900 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5901
5902 flush_sequence();
5903 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
5904 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
5905
5906 DestroyWindow(combo);
5907 DestroyWindow(parent);
5908 }
5909
5910 /****************** WM_IME_KEYDOWN message test *******************/
5911
5912 static const struct message WmImeKeydownMsgSeq_0[] =
5913 {
5914 { WM_IME_KEYDOWN, wparam, VK_RETURN },
5915 { WM_CHAR, wparam, 'A' },
5916 { 0 }
5917 };
5918
5919 static const struct message WmImeKeydownMsgSeq_1[] =
5920 {
5921 { WM_KEYDOWN, optional|wparam, VK_RETURN },
5922 { WM_CHAR, optional|wparam, VK_RETURN },
5923 { 0 }
5924 };
5925
5926 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5927 {
5928 struct recvd_message msg;
5929
5930 msg.hwnd = hwnd;
5931 msg.message = message;
5932 msg.flags = wparam|lparam;
5933 msg.wParam = wParam;
5934 msg.lParam = lParam;
5935 msg.descr = "wmime_keydown";
5936 add_message(&msg);
5937
5938 return DefWindowProcA(hwnd, message, wParam, lParam);
5939 }
5940
5941 static void register_wmime_keydown_class(void)
5942 {
5943 WNDCLASSA cls;
5944
5945 ZeroMemory(&cls, sizeof(WNDCLASSA));
5946 cls.lpfnWndProc = wmime_keydown_procA;
5947 cls.hInstance = GetModuleHandleA(0);
5948 cls.lpszClassName = "wmime_keydown_class";
5949 if (!RegisterClassA(&cls)) assert(0);
5950 }
5951
5952 static void test_wmime_keydown_message(void)
5953 {
5954 HWND hwnd;
5955 MSG msg;
5956
5957 trace("Message sequences by WM_IME_KEYDOWN\n");
5958
5959 register_wmime_keydown_class();
5960 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5961 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5962 NULL, NULL, 0);
5963 flush_events();
5964 flush_sequence();
5965
5966 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5967 SendMessageA(hwnd, WM_CHAR, 'A', 1);
5968 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5969
5970 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
5971 {
5972 TranslateMessage(&msg);
5973 DispatchMessageA(&msg);
5974 }
5975 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5976
5977 DestroyWindow(hwnd);
5978 }
5979
5980 /************* painting message test ********************/
5981
5982 void dump_region(HRGN hrgn)
5983 {
5984 DWORD i, size;
5985 RGNDATA *data = NULL;
5986 RECT *rect;
5987
5988 if (!hrgn)
5989 {
5990 printf( "null region\n" );
5991 return;
5992 }
5993 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5994 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5995 GetRegionData( hrgn, size, data );
5996 printf("%d rects:", data->rdh.nCount );
5997 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5998 printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5999 printf("\n");
6000 HeapFree( GetProcessHeap(), 0, data );
6001 }
6002
6003 static void check_update_rgn( HWND hwnd, HRGN hrgn )
6004 {
6005 INT ret;
6006 RECT r1, r2;
6007 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
6008 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
6009
6010 ret = GetUpdateRgn( hwnd, update, FALSE );
6011 ok( ret != ERROR, "GetUpdateRgn failed\n" );
6012 if (ret == NULLREGION)
6013 {
6014 ok( !hrgn, "Update region shouldn't be empty\n" );
6015 }
6016 else
6017 {
6018 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
6019 {
6020 ok( 0, "Regions are different\n" );
6021 if (winetest_debug > 0)
6022 {
6023 printf( "Update region: " );
6024 dump_region( update );
6025 printf( "Wanted region: " );
6026 dump_region( hrgn );
6027 }
6028 }
6029 }
6030 GetRgnBox( update, &r1 );
6031 GetUpdateRect( hwnd, &r2, FALSE );
6032 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
6033 "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
6034 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
6035
6036 DeleteObject( tmp );
6037 DeleteObject( update );
6038 }
6039
6040 static const struct message WmInvalidateRgn[] = {
6041 { WM_NCPAINT, sent },
6042 { WM_GETTEXT, sent|defwinproc|optional },
6043 { 0 }
6044 };
6045
6046 static const struct message WmGetUpdateRect[] = {
6047 { WM_NCPAINT, sent },
6048 { WM_GETTEXT, sent|defwinproc|optional },
6049 { WM_PAINT, sent },
6050 { 0 }
6051 };
6052
6053 static const struct message WmInvalidateFull[] = {
6054 { WM_NCPAINT, sent|wparam, 1 },
6055 { WM_GETTEXT, sent|defwinproc|optional },
6056 { 0 }
6057 };
6058
6059 static const struct message WmInvalidateErase[] = {
6060 { WM_NCPAINT, sent|wparam, 1 },
6061 { WM_GETTEXT, sent|defwinproc|optional },
6062 { WM_ERASEBKGND, sent },
6063 { 0 }
6064 };
6065
6066 static const struct message WmInvalidatePaint[] = {
6067 { WM_PAINT, sent },
6068 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
6069 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6070 { 0 }
6071 };
6072
6073 static const struct message WmInvalidateErasePaint[] = {
6074 { WM_PAINT, sent },
6075 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
6076 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6077 { WM_ERASEBKGND, sent|beginpaint|optional },
6078 { 0 }
6079 };
6080
6081 static const struct message WmInvalidateErasePaint2[] = {
6082 { WM_PAINT, sent },
6083 { WM_NCPAINT, sent|beginpaint },
6084 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6085 { WM_ERASEBKGND, sent|beginpaint|optional },
6086 { 0 }
6087 };
6088
6089 static const struct message WmErase[] = {
6090 { WM_ERASEBKGND, sent },
6091 { 0 }
6092 };
6093
6094 static const struct message WmPaint[] = {
6095 { WM_PAINT, sent },
6096 { 0 }
6097 };
6098
6099 static const struct message WmParentOnlyPaint[] = {
6100 { WM_PAINT, sent|parent },
6101 { 0 }
6102 };
6103
6104 static const struct message WmInvalidateParent[] = {
6105 { WM_NCPAINT, sent|parent },
6106 { WM_GETTEXT, sent|defwinproc|parent|optional },
6107 { WM_ERASEBKGND, sent|parent },
6108 { 0 }
6109 };
6110
6111 static const struct message WmInvalidateParentChild[] = {
6112 { WM_NCPAINT, sent|parent },
6113 { WM_GETTEXT, sent|defwinproc|parent|optional },
6114 { WM_ERASEBKGND, sent|parent },
6115 { WM_NCPAINT, sent },
6116 { WM_GETTEXT, sent|defwinproc|optional },
6117 { WM_ERASEBKGND, sent },
6118 { 0 }
6119 };
6120
6121 static const struct message WmInvalidateParentChild2[] = {
6122 { WM_ERASEBKGND, sent|parent },
6123 { WM_NCPAINT, sent },
6124 { WM_GETTEXT, sent|defwinproc|optional },
6125 { WM_ERASEBKGND, sent },
6126 { 0 }
6127 };
6128
6129 static const struct message WmParentPaint[] = {
6130 { WM_PAINT, sent|parent },
6131 { WM_PAINT, sent },
6132 { 0 }
6133 };
6134
6135 static const struct message WmParentPaintNc[] = {
6136 { WM_PAINT, sent|parent },
6137 { WM_PAINT, sent },
6138 { WM_NCPAINT, sent|beginpaint },
6139 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6140 { WM_ERASEBKGND, sent|beginpaint|optional },
6141 { 0 }
6142 };
6143
6144 static const struct message WmChildPaintNc[] = {
6145 { WM_PAINT, sent },
6146 { WM_NCPAINT, sent|beginpaint },
6147 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6148 { WM_ERASEBKGND, sent|beginpaint|optional },
6149 { 0 }
6150 };
6151
6152 static const struct message WmParentErasePaint[] = {
6153 { WM_PAINT, sent|parent },
6154 { WM_NCPAINT, sent|parent|beginpaint },
6155 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6156 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
6157 { WM_PAINT, sent },
6158 { WM_NCPAINT, sent|beginpaint },
6159 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6160 { WM_ERASEBKGND, sent|beginpaint|optional },
6161 { 0 }
6162 };
6163
6164 static const struct message WmParentOnlyNcPaint[] = {
6165 { WM_PAINT, sent|parent },
6166 { WM_NCPAINT, sent|parent|beginpaint },
6167 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6168 { 0 }
6169 };
6170
6171 static const struct message WmSetParentStyle[] = {
6172 { WM_STYLECHANGING, sent|parent },
6173 { WM_STYLECHANGED, sent|parent },
6174 { 0 }
6175 };
6176
6177 static void test_paint_messages(void)
6178 {
6179 BOOL ret;
6180 RECT rect;
6181 POINT pt;
6182 MSG msg;
6183 HWND hparent, hchild;
6184 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6185 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
6186 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
6187 100, 100, 200, 200, 0, 0, 0, NULL);
6188 ok (hwnd != 0, "Failed to create overlapped window\n");
6189
6190 ShowWindow( hwnd, SW_SHOW );
6191 UpdateWindow( hwnd );
6192 flush_events();
6193 flush_sequence();
6194
6195 check_update_rgn( hwnd, 0 );
6196 SetRectRgn( hrgn, 10, 10, 20, 20 );
6197 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6198 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6199 check_update_rgn( hwnd, hrgn );
6200 SetRectRgn( hrgn2, 20, 20, 30, 30 );
6201 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
6202 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6203 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
6204 check_update_rgn( hwnd, hrgn );
6205 /* validate everything */
6206 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6207 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6208 check_update_rgn( hwnd, 0 );
6209
6210 /* test empty region */
6211 SetRectRgn( hrgn, 10, 10, 10, 15 );
6212 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6213 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6214 check_update_rgn( hwnd, 0 );
6215 /* test empty rect */
6216 SetRect( &rect, 10, 10, 10, 15 );
6217 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
6218 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6219 check_update_rgn( hwnd, 0 );
6220
6221 /* flush pending messages */
6222 flush_events();
6223 flush_sequence();
6224
6225 GetClientRect( hwnd, &rect );
6226 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
6227 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
6228 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6229 */
6230 trace("testing InvalidateRect(0, NULL, FALSE)\n");
6231 SetRectEmpty( &rect );
6232 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
6233 check_update_rgn( hwnd, hrgn );
6234 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6235 flush_events();
6236 ok_sequence( WmPaint, "Paint", FALSE );
6237 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6238 check_update_rgn( hwnd, 0 );
6239
6240 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
6241 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6242 */
6243 trace("testing ValidateRect(0, NULL)\n");
6244 SetRectEmpty( &rect );
6245 if (ValidateRect(0, &rect)) /* not supported on Win9x */
6246 {
6247 check_update_rgn( hwnd, hrgn );
6248 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6249 flush_events();
6250 ok_sequence( WmPaint, "Paint", FALSE );
6251 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6252 check_update_rgn( hwnd, 0 );
6253 }
6254
6255 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
6256 SetLastError(0xdeadbeef);
6257 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
6258 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
6259 "wrong error code %d\n", GetLastError());
6260 check_update_rgn( hwnd, 0 );
6261 flush_events();
6262 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6263
6264 trace("testing ValidateRgn(0, NULL)\n");
6265 SetLastError(0xdeadbeef);
6266 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6267 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6268 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6269 "wrong error code %d\n", GetLastError());
6270 check_update_rgn( hwnd, 0 );
6271 flush_events();
6272 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6273
6274 trace("testing UpdateWindow(NULL)\n");
6275 SetLastError(0xdeadbeef);
6276 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
6277 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6278 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6279 "wrong error code %d\n", GetLastError());
6280 check_update_rgn( hwnd, 0 );
6281 flush_events();
6282 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6283
6284 /* now with frame */
6285 SetRectRgn( hrgn, -5, -5, 20, 20 );
6286
6287 /* flush pending messages */
6288 flush_events();
6289 flush_sequence();
6290 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6291 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6292
6293 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
6294 check_update_rgn( hwnd, hrgn );
6295
6296 flush_sequence();
6297 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6298 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6299
6300 flush_sequence();
6301 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6302 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6303
6304 GetClientRect( hwnd, &rect );
6305 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6306 check_update_rgn( hwnd, hrgn );
6307
6308 flush_sequence();
6309 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6310 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6311
6312 flush_sequence();
6313 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6314 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6315 check_update_rgn( hwnd, 0 );
6316
6317 flush_sequence();
6318 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6319 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6320 check_update_rgn( hwnd, 0 );
6321
6322 flush_sequence();
6323 SetRectRgn( hrgn, 0, 0, 100, 100 );
6324 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6325 SetRectRgn( hrgn, 0, 0, 50, 100 );
6326 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6327 SetRectRgn( hrgn, 50, 0, 100, 100 );
6328 check_update_rgn( hwnd, hrgn );
6329 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6330 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
6331 check_update_rgn( hwnd, 0 );
6332
6333 flush_sequence();
6334 SetRectRgn( hrgn, 0, 0, 100, 100 );
6335 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6336 SetRectRgn( hrgn, 0, 0, 100, 50 );
6337 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6338 ok_sequence( WmErase, "Erase", FALSE );
6339 SetRectRgn( hrgn, 0, 50, 100, 100 );
6340 check_update_rgn( hwnd, hrgn );
6341
6342 flush_sequence();
6343 SetRectRgn( hrgn, 0, 0, 100, 100 );
6344 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6345 SetRectRgn( hrgn, 0, 0, 50, 50 );
6346 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6347 ok_sequence( WmPaint, "Paint", FALSE );
6348
6349 flush_sequence();
6350 SetRectRgn( hrgn, -4, -4, -2, -2 );
6351 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6352 SetRectRgn( hrgn, -200, -200, -198, -198 );
6353 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6354 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6355
6356 flush_sequence();
6357 SetRectRgn( hrgn, -4, -4, -2, -2 );
6358 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6359 SetRectRgn( hrgn, -4, -4, -3, -3 );
6360 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6361 SetRectRgn( hrgn, 0, 0, 1, 1 );
6362 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6363 ok_sequence( WmPaint, "Paint", FALSE );
6364
6365 flush_sequence();
6366 SetRectRgn( hrgn, -4, -4, -1, -1 );
6367 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6368 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6369 /* make sure no WM_PAINT was generated */
6370 flush_events();
6371 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6372
6373 flush_sequence();
6374 SetRectRgn( hrgn, -4, -4, -1, -1 );
6375 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6376 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
6377 {
6378 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6379 {
6380 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6381 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6382 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6383 ret = GetUpdateRect( hwnd, &rect, FALSE );
6384 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6385 /* this will send WM_NCPAINT and validate the non client area */
6386 ret = GetUpdateRect( hwnd, &rect, TRUE );
6387 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6388 }
6389 DispatchMessageA( &msg );
6390 }
6391 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6392
6393 DestroyWindow( hwnd );
6394
6395 /* now test with a child window */
6396
6397 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6398 100, 100, 200, 200, 0, 0, 0, NULL);
6399 ok (hparent != 0, "Failed to create parent window\n");
6400
6401 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6402 10, 10, 100, 100, hparent, 0, 0, NULL);
6403 ok (hchild != 0, "Failed to create child window\n");
6404
6405 ShowWindow( hparent, SW_SHOW );
6406 UpdateWindow( hparent );
6407 UpdateWindow( hchild );
6408 flush_events();
6409 flush_sequence();
6410 log_all_parent_messages++;
6411
6412 SetRect( &rect, 0, 0, 50, 50 );
6413 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6414 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6415 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6416
6417 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6418 pt.x = pt.y = 0;
6419 MapWindowPoints( hchild, hparent, &pt, 1 );
6420 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6421 check_update_rgn( hchild, hrgn );
6422 SetRectRgn( hrgn, 0, 0, 50, 50 );
6423 check_update_rgn( hparent, hrgn );
6424 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6425 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6426 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6427 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6428
6429 flush_events();
6430 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6431
6432 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6433 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6434 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6435 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6436 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6437
6438 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6439 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6440 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6441
6442 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6443 flush_sequence();
6444 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6445 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6446 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6447
6448 /* flush all paint messages */
6449 flush_events();
6450 flush_sequence();
6451
6452 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6453 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6454 SetRectRgn( hrgn, 0, 0, 50, 50 );
6455 check_update_rgn( hparent, hrgn );
6456 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6457 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6458 SetRectRgn( hrgn, 0, 0, 50, 50 );
6459 check_update_rgn( hparent, hrgn );
6460
6461 /* flush all paint messages */
6462 flush_events();
6463 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6464 flush_sequence();
6465
6466 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6467 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6468 SetRectRgn( hrgn, 0, 0, 50, 50 );
6469 check_update_rgn( hparent, hrgn );
6470 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6471 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6472 SetRectRgn( hrgn2, 10, 10, 50, 50 );
6473 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6474 check_update_rgn( hparent, hrgn );
6475 /* flush all paint messages */
6476 flush_events();
6477 flush_sequence();
6478
6479 /* same as above but parent gets completely validated */
6480 SetRect( &rect, 20, 20, 30, 30 );
6481 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6482 SetRectRgn( hrgn, 20, 20, 30, 30 );
6483 check_update_rgn( hparent, hrgn );
6484 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6485 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6486 check_update_rgn( hparent, 0 ); /* no update region */
6487 flush_events();
6488 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
6489
6490 /* make sure RDW_VALIDATE on child doesn't have the same effect */
6491 flush_sequence();
6492 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6493 SetRectRgn( hrgn, 20, 20, 30, 30 );
6494 check_update_rgn( hparent, hrgn );
6495 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6496 SetRectRgn( hrgn, 20, 20, 30, 30 );
6497 check_update_rgn( hparent, hrgn );
6498
6499 /* same as above but normal WM_PAINT doesn't validate parent */
6500 flush_sequence();
6501 SetRect( &rect, 20, 20, 30, 30 );
6502 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6503 SetRectRgn( hrgn, 20, 20, 30, 30 );
6504 check_update_rgn( hparent, hrgn );
6505 /* no WM_PAINT in child while parent still pending */
6506 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6507 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6508 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6509 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6510
6511 flush_sequence();
6512 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6513 /* no WM_PAINT in child while parent still pending */
6514 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6515 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6516 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6517 /* now that parent is valid child should get WM_PAINT */
6518 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6519 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6520 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6521 ok_sequence( WmEmptySeq, "No other message", FALSE );
6522
6523 /* same thing with WS_CLIPCHILDREN in parent */
6524 flush_sequence();
6525 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6526 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6527 /* changing style invalidates non client area, but we need to invalidate something else to see it */
6528 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6529 ok_sequence( WmEmptySeq, "No message", FALSE );
6530 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6531 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6532
6533 flush_sequence();
6534 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6535 SetRectRgn( hrgn, 20, 20, 30, 30 );
6536 check_update_rgn( hparent, hrgn );
6537 /* no WM_PAINT in child while parent still pending */
6538 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6539 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6540 /* WM_PAINT in parent first */
6541 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6542 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6543
6544 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6545 flush_sequence();
6546 SetRect( &rect, 0, 0, 30, 30 );
6547 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6548 SetRectRgn( hrgn, 0, 0, 30, 30 );
6549 check_update_rgn( hparent, hrgn );
6550 flush_events();
6551 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6552
6553 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6554 flush_sequence();
6555 SetRect( &rect, -10, 0, 30, 30 );
6556 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6557 SetRect( &rect, 0, 0, 20, 20 );
6558 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6559 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6560 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6561
6562 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6563 flush_sequence();
6564 SetRect( &rect, -10, 0, 30, 30 );
6565 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6566 SetRect( &rect, 0, 0, 100, 100 );
6567 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6568 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6569 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6570 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6571 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6572
6573 /* test RDW_INTERNALPAINT behavior */
6574
6575 flush_sequence();
6576 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6577 flush_events();
6578 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6579
6580 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6581 flush_events();
6582 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6583
6584 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6585 flush_events();
6586 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6587
6588 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6589 UpdateWindow( hparent );
6590 flush_events();
6591 flush_sequence();
6592 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6593 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6594 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6595 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6596 flush_events();
6597 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6598
6599 UpdateWindow( hparent );
6600 flush_events();
6601 flush_sequence();
6602 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6603 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6604 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6605 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6606 flush_events();
6607 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6608
6609 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6610 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6611 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6612 flush_events();
6613 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6614
6615 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6616 UpdateWindow( hparent );
6617 flush_events();
6618 flush_sequence();
6619 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6620 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6621 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6622 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6623 flush_events();
6624 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6625
6626 UpdateWindow( hparent );
6627 flush_events();
6628 flush_sequence();
6629 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6630 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6631 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6632 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6633 flush_events();
6634 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6635
6636 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6637 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6638
6639 UpdateWindow( hparent );
6640 flush_events();
6641 flush_sequence();
6642 trace("testing SetWindowPos(-10000, -10000) on child\n");
6643 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6644 check_update_rgn( hchild, 0 );
6645 flush_events();
6646
6647 #if 0 /* this one doesn't pass under Wine yet */
6648 UpdateWindow( hparent );
6649 flush_events();
6650 flush_sequence();
6651 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6652 ShowWindow( hchild, SW_MINIMIZE );
6653 check_update_rgn( hchild, 0 );
6654 flush_events();
6655 #endif
6656
6657 UpdateWindow( hparent );
6658 flush_events();
6659 flush_sequence();
6660 trace("testing SetWindowPos(-10000, -10000) on parent\n");
6661 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6662 check_update_rgn( hparent, 0 );
6663 flush_events();
6664
6665 log_all_parent_messages--;
6666 DestroyWindow( hparent );
6667 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6668
6669 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6670
6671 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6672 100, 100, 200, 200, 0, 0, 0, NULL);
6673 ok (hparent != 0, "Failed to create parent window\n");
6674
6675 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6676 10, 10, 100, 100, hparent, 0, 0, NULL);
6677 ok (hchild != 0, "Failed to create child window\n");
6678
6679 ShowWindow( hparent, SW_SHOW );
6680 UpdateWindow( hparent );
6681 UpdateWindow( hchild );
6682 flush_events();
6683 flush_sequence();
6684
6685 /* moving child outside of parent boundaries changes update region */
6686 SetRect( &rect, 0, 0, 40, 40 );
6687 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6688 SetRectRgn( hrgn, 0, 0, 40, 40 );
6689 check_update_rgn( hchild, hrgn );
6690 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6691 SetRectRgn( hrgn, 10, 0, 40, 40 );
6692 check_update_rgn( hchild, hrgn );
6693 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6694 SetRectRgn( hrgn, 10, 10, 40, 40 );
6695 check_update_rgn( hchild, hrgn );
6696
6697 /* moving parent off-screen does too */
6698 SetRect( &rect, 0, 0, 100, 100 );
6699 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6700 SetRectRgn( hrgn, 0, 0, 100, 100 );
6701 check_update_rgn( hparent, hrgn );
6702 SetRectRgn( hrgn, 10, 10, 40, 40 );
6703 check_update_rgn( hchild, hrgn );
6704 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6705 SetRectRgn( hrgn, 20, 20, 100, 100 );
6706 check_update_rgn( hparent, hrgn );
6707 SetRectRgn( hrgn, 30, 30, 40, 40 );
6708 check_update_rgn( hchild, hrgn );
6709
6710 /* invalidated region is cropped by the parent rects */
6711 SetRect( &rect, 0, 0, 50, 50 );
6712 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6713 SetRectRgn( hrgn, 30, 30, 50, 50 );
6714 check_update_rgn( hchild, hrgn );
6715
6716 DestroyWindow( hparent );
6717 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6718 flush_sequence();
6719
6720 DeleteObject( hrgn );
6721 DeleteObject( hrgn2 );
6722 }
6723
6724 struct wnd_event
6725 {
6726 HWND hwnd;
6727 HANDLE grand_child;
6728 HANDLE start_event;
6729 HANDLE stop_event;
6730 };
6731
6732 static DWORD WINAPI thread_proc(void *param)
6733 {
6734 MSG msg;
6735 struct wnd_event *wnd_event = param;
6736
6737 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6738 100, 100, 200, 200, 0, 0, 0, NULL);
6739 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6740
6741 SetEvent(wnd_event->start_event);
6742
6743 while (GetMessageA(&msg, 0, 0, 0))
6744 {
6745 TranslateMessage(&msg);
6746 DispatchMessageA(&msg);
6747 }
6748
6749 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6750
6751 return 0;
6752 }
6753
6754 static DWORD CALLBACK create_grand_child_thread( void *param )
6755 {
6756 struct wnd_event *wnd_event = param;
6757 HWND hchild;
6758 MSG msg;
6759
6760 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6761 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6762 ok (hchild != 0, "Failed to create child window\n");
6763 flush_events();
6764 flush_sequence();
6765 SetEvent( wnd_event->start_event );
6766
6767 for (;;)
6768 {
6769 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6770 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
6771 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6772 }
6773 return 0;
6774 }
6775
6776 static DWORD CALLBACK create_child_thread( void *param )
6777 {
6778 struct wnd_event *wnd_event = param;
6779 struct wnd_event child_event;
6780 DWORD ret, tid;
6781 MSG msg;
6782
6783 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6784 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6785 ok (child_event.hwnd != 0, "Failed to create child window\n");
6786 SetFocus( child_event.hwnd );
6787 flush_events();
6788 flush_sequence();
6789 child_event.start_event = wnd_event->start_event;
6790 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6791 for (;;)
6792 {
6793 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6794 if (ret != 1) break;
6795 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6796 }
6797 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6798 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6799 return 0;
6800 }
6801
6802 static const char manifest_dep[] =
6803 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
6804 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
6805 " <file name=\"testdep.dll\" />"
6806 "</assembly>";
6807
6808 static const char manifest_main[] =
6809 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
6810 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
6811 "<dependency>"
6812 " <dependentAssembly>"
6813 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
6814 " </dependentAssembly>"
6815 "</dependency>"
6816 "</assembly>";
6817
6818 static void create_manifest_file(const char *filename, const char *manifest)
6819 {
6820 WCHAR path[MAX_PATH];
6821 HANDLE file;
6822 DWORD size;
6823
6824 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
6825 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6826 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
6827 WriteFile(file, manifest, strlen(manifest), &size, NULL);
6828 CloseHandle(file);
6829 }
6830
6831 static HANDLE test_create(const char *file)
6832 {
6833 WCHAR path[MAX_PATH];
6834 ACTCTXW actctx;
6835 HANDLE handle;
6836
6837 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
6838 memset(&actctx, 0, sizeof(ACTCTXW));
6839 actctx.cbSize = sizeof(ACTCTXW);
6840 actctx.lpSource = path;
6841
6842 handle = pCreateActCtxW(&actctx);
6843 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
6844
6845 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
6846 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
6847 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
6848 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
6849 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
6850 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
6851 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
6852 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
6853 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
6854
6855 return handle;
6856 }
6857
6858 static void test_interthread_messages(void)
6859 {
6860 HANDLE hThread, context, handle, event;
6861 ULONG_PTR cookie;
6862 DWORD tid;
6863 WNDPROC proc;
6864 MSG msg;
6865 char buf[256];
6866 int len, expected_len;
6867 struct wnd_event wnd_event;
6868 BOOL ret;
6869
6870 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6871 if (!wnd_event.start_event)
6872 {
6873 win_skip("skipping interthread message test under win9x\n");
6874 return;
6875 }
6876
6877 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6878 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6879
6880 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6881
6882 CloseHandle(wnd_event.start_event);
6883
6884 SetLastError(0xdeadbeef);
6885 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
6886 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6887 "wrong error code %d\n", GetLastError());
6888
6889 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6890 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6891
6892 expected_len = lstrlenA("window caption text");
6893 memset(buf, 0, sizeof(buf));
6894 SetLastError(0xdeadbeef);
6895 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6896 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6897 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6898
6899 msg.hwnd = wnd_event.hwnd;
6900 msg.message = WM_GETTEXT;
6901 msg.wParam = sizeof(buf);
6902 msg.lParam = (LPARAM)buf;
6903 memset(buf, 0, sizeof(buf));
6904 SetLastError(0xdeadbeef);
6905 len = DispatchMessageA(&msg);
6906 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6907 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
6908
6909 /* the following test causes an exception in user.exe under win9x */
6910 msg.hwnd = wnd_event.hwnd;
6911 msg.message = WM_TIMER;
6912 msg.wParam = 0;
6913 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6914 SetLastError(0xdeadbeef);
6915 len = DispatchMessageA(&msg);
6916 ok(!len && GetLastError() == 0xdeadbeef,
6917 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6918
6919 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6920 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6921
6922 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6923 CloseHandle(hThread);
6924
6925 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6926
6927 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6928 100, 100, 200, 200, 0, 0, 0, NULL);
6929 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6930 flush_events();
6931 flush_sequence();
6932 log_all_parent_messages++;
6933 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6934 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6935 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6936 for (;;)
6937 {
6938 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6939 if (ret != 1) break;
6940 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6941 }
6942 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6943 /* now wait for the thread without processing messages; this shouldn't deadlock */
6944 SetEvent( wnd_event.stop_event );
6945 ret = WaitForSingleObject( hThread, 5000 );
6946 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6947 CloseHandle( hThread );
6948
6949 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6950 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6951 CloseHandle( wnd_event.grand_child );
6952
6953 CloseHandle( wnd_event.start_event );
6954 CloseHandle( wnd_event.stop_event );
6955 flush_events();
6956 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6957 log_all_parent_messages--;
6958 DestroyWindow( wnd_event.hwnd );
6959
6960 /* activation context tests */
6961 if (!pActivateActCtx)
6962 {
6963 win_skip("Activation contexts are not supported, skipping\n");
6964 return;
6965 }
6966
6967 create_manifest_file("testdep1.manifest", manifest_dep);
6968 create_manifest_file("main.manifest", manifest_main);
6969
6970 context = test_create("main.manifest");
6971 DeleteFileA("testdep1.manifest");
6972 DeleteFileA("main.manifest");
6973
6974 handle = (void*)0xdeadbeef;
6975 ret = pGetCurrentActCtx(&handle);
6976 ok(ret, "GetCurentActCtx failed: %u\n", GetLastError());
6977 ok(handle == 0, "active context %p\n", handle);
6978
6979 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6980 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6981 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6982 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6983 CloseHandle(wnd_event.start_event);
6984
6985 /* context is activated after thread creation, so it doesn't inherit it by default */
6986 ret = pActivateActCtx(context, &cookie);
6987 ok(ret, "activation failed: %u\n", GetLastError());
6988
6989 handle = 0;
6990 ret = pGetCurrentActCtx(&handle);
6991 ok(ret, "GetCurentActCtx failed: %u\n", GetLastError());
6992 ok(handle != 0, "active context %p\n", handle);
6993
6994 /* destination window will test for active context */
6995 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
6996 ok(ret, "thread window returned %d\n", ret);
6997
6998 event = CreateEventW(NULL, 0, 0, NULL);
6999 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
7000 ok(ret, "thread window returned %d\n", ret);
7001 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7002 CloseHandle(event);
7003
7004 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
7005 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
7006
7007 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7008 CloseHandle(hThread);
7009
7010 ret = pDeactivateActCtx(0, cookie);
7011 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
7012 pReleaseActCtx(context);
7013 }
7014
7015
7016 static const struct message WmVkN[] = {
7017 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7018 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7019 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7020 { WM_CHAR, wparam|lparam, 'n', 1 },
7021 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
7022 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7023 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7024 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7025 { 0 }
7026 };
7027 static const struct message WmShiftVkN[] = {
7028 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7029 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7030 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7031 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7032 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7033 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7034 { WM_CHAR, wparam|lparam, 'N', 1 },
7035 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
7036 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7037 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7038 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7039 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7040 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7041 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7042 { 0 }
7043 };
7044 static const struct message WmCtrlVkN[] = {
7045 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7046 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7047 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7048 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7049 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7050 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7051 { WM_CHAR, wparam|lparam, 0x000e, 1 },
7052 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
7053 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7054 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7055 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7056 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7057 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7058 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7059 { 0 }
7060 };
7061 static const struct message WmCtrlVkN_2[] = {
7062 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7063 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7064 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7065 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7066 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7067 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
7068 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7069 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7070 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7071 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7072 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7073 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7074 { 0 }
7075 };
7076 static const struct message WmAltVkN[] = {
7077 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7078 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7079 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7080 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7081 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
7082 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
7083 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
7084 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
7085 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
7086 { HCBT_SYSCOMMAND, hook },
7087 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7088 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7089 { 0x00AE, sent|defwinproc|optional }, /* XP */
7090 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
7091 { WM_INITMENU, sent|defwinproc },
7092 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7093 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
7094 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7095 { WM_CAPTURECHANGED, sent|defwinproc },
7096 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
7097 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7098 { WM_EXITMENULOOP, sent|defwinproc },
7099 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
7100 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
7101 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7102 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
7103 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7104 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7105 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7106 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7107 { 0 }
7108 };
7109 static const struct message WmAltVkN_2[] = {
7110 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7111 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7112 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7113 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7114 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
7115 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
7116 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7117 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
7118 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7119 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7120 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7121 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7122 { 0 }
7123 };
7124 static const struct message WmCtrlAltVkN[] = {
7125 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7126 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7127 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7128 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7129 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7130 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7131 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7132 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
7133 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
7134 { WM_CHAR, optional },
7135 { WM_CHAR, sent|optional },
7136 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7137 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
7138 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7139 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7140 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7141 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7142 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7143 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7144 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7145 { 0 }
7146 };
7147 static const struct message WmCtrlShiftVkN[] = {
7148 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7149 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7150 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7151 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7152 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7153 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7154 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7155 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7156 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
7157 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7158 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7159 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7160 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7161 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7162 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7163 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7164 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7165 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7166 { 0 }
7167 };
7168 static const struct message WmCtrlAltShiftVkN[] = {
7169 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7170 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7171 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7172 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7173 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7174 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7175 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
7176 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
7177 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
7178 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7179 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
7180 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
7181 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7182 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
7183 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7184 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
7185 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
7186 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
7187 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7188 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7189 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7190 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7191 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7192 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7193 { 0 }
7194 };
7195 static const struct message WmAltPressRelease[] = {
7196 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7197 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7198 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7199 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7200 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7201 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7202 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
7203 { HCBT_SYSCOMMAND, hook },
7204 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7205 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7206 { WM_INITMENU, sent|defwinproc },
7207 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7208 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7209 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7210
7211 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
7212
7213 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7214 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7215 { WM_CAPTURECHANGED, sent|defwinproc },
7216 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7217 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7218 { WM_EXITMENULOOP, sent|defwinproc },
7219 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7220 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7221 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7222 { 0 }
7223 };
7224 static const struct message WmShiftMouseButton[] = {
7225 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7226 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7227 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7228 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
7229 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
7230 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
7231 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
7232 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
7233 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
7234 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7235 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7236 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7237 { 0 }
7238 };
7239 static const struct message WmF1Seq[] = {
7240 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
7241 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
7242 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
7243 { WM_KEYF1, wparam|lparam, 0, 0 },
7244 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
7245 { WM_HELP, sent|defwinproc },
7246 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
7247 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
7248 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
7249 { 0 }
7250 };
7251 static const struct message WmVkAppsSeq[] = {
7252 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
7253 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
7254 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
7255 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
7256 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
7257 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
7258 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
7259 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
7260 { 0 }
7261 };
7262 static const struct message WmVkF10Seq[] = {
7263 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7264 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7265 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7266 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7267 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7268 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7269 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7270 { HCBT_SYSCOMMAND, hook },
7271 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7272 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7273 { WM_INITMENU, sent|defwinproc },
7274 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7275 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7276 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7277
7278 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
7279
7280 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7281 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7282 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7283 { WM_CAPTURECHANGED, sent|defwinproc },
7284 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7285 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7286 { WM_EXITMENULOOP, sent|defwinproc },
7287 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7288 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7289 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7290 { 0 }
7291 };
7292 static const struct message WmShiftF10Seq[] = {
7293 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7294 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7295 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
7296 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7297 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7298 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7299 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
7300 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7301 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7302 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7303 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7304 { HCBT_SYSCOMMAND, hook },
7305 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7306 { WM_INITMENU, sent|defwinproc },
7307 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7308 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
7309 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
7310 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
7311 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
7312 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7313 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
7314 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
7315 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
7316 { 0 }
7317 };
7318
7319 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
7320 {
7321 MSG msg;
7322
7323 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
7324 {
7325 struct recvd_message log_msg;
7326
7327 /* ignore some unwanted messages */
7328 if (msg.message == WM_MOUSEMOVE ||
7329 msg.message == WM_TIMER ||
7330 ignore_message( msg.message ))
7331 continue;
7332
7333 log_msg.hwnd = msg.hwnd;
7334 log_msg.message = msg.message;
7335 log_msg.flags = wparam|lparam;
7336 log_msg.wParam = msg.wParam;
7337 log_msg.lParam = msg.lParam;
7338 log_msg.descr = "accel";
7339 add_message(&log_msg);
7340
7341 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
7342 {
7343 TranslateMessage(&msg);
7344 DispatchMessageA(&msg);
7345 }
7346 }
7347 }
7348
7349 static void test_accelerators(void)
7350 {
7351 RECT rc;
7352 POINT pt;
7353 SHORT state;
7354 HACCEL hAccel;
7355 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7356 100, 100, 200, 200, 0, 0, 0, NULL);
7357 BOOL ret;
7358
7359 assert(hwnd != 0);
7360 UpdateWindow(hwnd);
7361 flush_events();
7362 flush_sequence();
7363
7364 SetFocus(hwnd);
7365 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
7366
7367 state = GetKeyState(VK_SHIFT);
7368 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
7369 state = GetKeyState(VK_CAPITAL);
7370 ok(state == 0, "wrong CapsLock state %04x\n", state);
7371
7372 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
7373 assert(hAccel != 0);
7374
7375 flush_events();
7376 pump_msg_loop(hwnd, 0);
7377 flush_sequence();
7378
7379 trace("testing VK_N press/release\n");
7380 flush_sequence();
7381 keybd_event('N', 0, 0, 0);
7382 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7383 pump_msg_loop(hwnd, hAccel);
7384 if (!sequence_cnt) /* we didn't get any message */
7385 {
7386 skip( "queuing key events not supported\n" );
7387 goto done;
7388 }
7389 ok_sequence(WmVkN, "VK_N press/release", FALSE);
7390
7391 trace("testing Shift+VK_N press/release\n");
7392 flush_sequence();
7393 keybd_event(VK_SHIFT, 0, 0, 0);
7394 keybd_event('N', 0, 0, 0);
7395 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7396 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7397 pump_msg_loop(hwnd, hAccel);
7398 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7399
7400 trace("testing Ctrl+VK_N press/release\n");
7401 flush_sequence();
7402 keybd_event(VK_CONTROL, 0, 0, 0);
7403 keybd_event('N', 0, 0, 0);
7404 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7405 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7406 pump_msg_loop(hwnd, hAccel);
7407 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
7408
7409 trace("testing Alt+VK_N press/release\n");
7410 flush_sequence();
7411 keybd_event(VK_MENU, 0, 0, 0);
7412 keybd_event('N', 0, 0, 0);
7413 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7414 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7415 pump_msg_loop(hwnd, hAccel);
7416 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
7417
7418 trace("testing Ctrl+Alt+VK_N press/release 1\n");
7419 flush_sequence();
7420 keybd_event(VK_CONTROL, 0, 0, 0);
7421 keybd_event(VK_MENU, 0, 0, 0);
7422 keybd_event('N', 0, 0, 0);
7423 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7424 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7425 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7426 pump_msg_loop(hwnd, hAccel);
7427 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
7428
7429 ret = DestroyAcceleratorTable(hAccel);
7430 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7431
7432 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
7433 assert(hAccel != 0);
7434
7435 trace("testing VK_N press/release\n");
7436 flush_sequence();
7437 keybd_event('N', 0, 0, 0);
7438 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7439 pump_msg_loop(hwnd, hAccel);
7440 ok_sequence(WmVkN, "VK_N press/release", FALSE);
7441
7442 trace("testing Shift+VK_N press/release\n");
7443 flush_sequence();
7444 keybd_event(VK_SHIFT, 0, 0, 0);
7445 keybd_event('N', 0, 0, 0);
7446 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7447 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7448 pump_msg_loop(hwnd, hAccel);
7449 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7450
7451 trace("testing Ctrl+VK_N press/release 2\n");
7452 flush_sequence();
7453 keybd_event(VK_CONTROL, 0, 0, 0);
7454 keybd_event('N', 0, 0, 0);
7455 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7456 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7457 pump_msg_loop(hwnd, hAccel);
7458 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7459
7460 trace("testing Alt+VK_N press/release 2\n");
7461 flush_sequence();
7462 keybd_event(VK_MENU, 0, 0, 0);
7463 keybd_event('N', 0, 0, 0);
7464 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7465 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7466 pump_msg_loop(hwnd, hAccel);
7467 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7468
7469 trace("testing Ctrl+Alt+VK_N press/release 2\n");
7470 flush_sequence();
7471 keybd_event(VK_CONTROL, 0, 0, 0);
7472 keybd_event(VK_MENU, 0, 0, 0);
7473 keybd_event('N', 0, 0, 0);
7474 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7475 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7476 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7477 pump_msg_loop(hwnd, hAccel);
7478 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7479
7480 trace("testing Ctrl+Shift+VK_N press/release\n");
7481 flush_sequence();
7482 keybd_event(VK_CONTROL, 0, 0, 0);
7483 keybd_event(VK_SHIFT, 0, 0, 0);
7484 keybd_event('N', 0, 0, 0);
7485 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7486 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7487 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7488 pump_msg_loop(hwnd, hAccel);
7489 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7490
7491 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7492 flush_sequence();
7493 keybd_event(VK_CONTROL, 0, 0, 0);
7494 keybd_event(VK_MENU, 0, 0, 0);
7495 keybd_event(VK_SHIFT, 0, 0, 0);
7496 keybd_event('N', 0, 0, 0);
7497 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7498 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7499 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7500 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7501 pump_msg_loop(hwnd, hAccel);
7502 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7503
7504 ret = DestroyAcceleratorTable(hAccel);
7505 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7506 hAccel = 0;
7507
7508 trace("testing Alt press/release\n");
7509 flush_sequence();
7510 keybd_event(VK_MENU, 0, 0, 0);
7511 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7512 keybd_event(VK_MENU, 0, 0, 0);
7513 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7514 pump_msg_loop(hwnd, 0);
7515 /* this test doesn't pass in Wine for managed windows */
7516 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7517
7518 trace("testing VK_F1 press/release\n");
7519 keybd_event(VK_F1, 0, 0, 0);
7520 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7521 pump_msg_loop(hwnd, 0);
7522 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7523
7524 trace("testing VK_APPS press/release\n");
7525 keybd_event(VK_APPS, 0, 0, 0);
7526 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7527 pump_msg_loop(hwnd, 0);
7528 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7529
7530 trace("testing VK_F10 press/release\n");
7531 keybd_event(VK_F10, 0, 0, 0);
7532 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7533 keybd_event(VK_F10, 0, 0, 0);
7534 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7535 pump_msg_loop(hwnd, 0);
7536 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
7537
7538 trace("testing SHIFT+F10 press/release\n");
7539 keybd_event(VK_SHIFT, 0, 0, 0);
7540 keybd_event(VK_F10, 0, 0, 0);
7541 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7542 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7543 keybd_event(VK_ESCAPE, 0, 0, 0);
7544 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
7545 pump_msg_loop(hwnd, 0);
7546 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
7547
7548 trace("testing Shift+MouseButton press/release\n");
7549 /* first, move mouse pointer inside of the window client area */
7550 GetClientRect(hwnd, &rc);
7551 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7552 rc.left += (rc.right - rc.left)/2;
7553 rc.top += (rc.bottom - rc.top)/2;
7554 SetCursorPos(rc.left, rc.top);
7555 SetActiveWindow(hwnd);
7556
7557 flush_events();
7558 flush_sequence();
7559 GetCursorPos(&pt);
7560 if (pt.x == rc.left && pt.y == rc.top)
7561 {
7562 int i;
7563 keybd_event(VK_SHIFT, 0, 0, 0);
7564 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7565 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7566 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7567 pump_msg_loop(hwnd, 0);
7568 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7569 if (i < sequence_cnt)
7570 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7571 else
7572 skip( "Shift+MouseButton event didn't get to the window\n" );
7573 }
7574
7575 done:
7576 if (hAccel) DestroyAcceleratorTable(hAccel);
7577 DestroyWindow(hwnd);
7578 }
7579
7580 /************* window procedures ********************/
7581
7582 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
7583 WPARAM wParam, LPARAM lParam)
7584 {
7585 static LONG defwndproc_counter = 0;
7586 static LONG beginpaint_counter = 0;
7587 LRESULT ret;
7588 struct recvd_message msg;
7589
7590 if (ignore_message( message )) return 0;
7591
7592 switch (message)
7593 {
7594 case WM_ENABLE:
7595 {
7596 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7597 ok((BOOL)wParam == !(style & WS_DISABLED),
7598 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7599 break;
7600 }
7601
7602 case WM_CAPTURECHANGED:
7603 if (test_DestroyWindow_flag)
7604 {
7605 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7606 if (style & WS_CHILD)
7607 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7608 else if (style & WS_POPUP)
7609 lParam = WND_POPUP_ID;
7610 else
7611 lParam = WND_PARENT_ID;
7612 }
7613 break;
7614
7615 case WM_NCDESTROY:
7616 {
7617 HWND capture;
7618
7619 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7620 capture = GetCapture();
7621 if (capture)
7622 {
7623 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7624 trace("current capture %p, releasing...\n", capture);
7625 ReleaseCapture();
7626 }
7627 }
7628 /* fall through */
7629 case WM_DESTROY:
7630 if (pGetAncestor)
7631 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7632 if (test_DestroyWindow_flag)
7633 {
7634 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7635 if (style & WS_CHILD)
7636 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7637 else if (style & WS_POPUP)
7638 lParam = WND_POPUP_ID;
7639 else
7640 lParam = WND_PARENT_ID;
7641 }
7642 break;
7643
7644 /* test_accelerators() depends on this */
7645 case WM_NCHITTEST:
7646 return HTCLIENT;
7647
7648 case WM_USER+10:
7649 {
7650 HANDLE handle, event = (HANDLE)lParam;
7651 BOOL ret;
7652
7653 handle = (void*)0xdeadbeef;
7654 ret = pGetCurrentActCtx(&handle);
7655 ok(ret, "failed to get current context, %u\n", GetLastError());
7656 ok(handle == 0, "got active context %p\n", handle);
7657 if (event) SetEvent(event);
7658 return 1;
7659 }
7660
7661 /* ignore */
7662 case WM_MOUSEMOVE:
7663 case WM_MOUSEACTIVATE:
7664 case WM_NCMOUSEMOVE:
7665 case WM_SETCURSOR:
7666 case WM_IME_SELECT:
7667 return 0;
7668 }
7669
7670 msg.hwnd = hwnd;
7671 msg.message = message;
7672 msg.flags = sent|wparam|lparam;
7673 if (defwndproc_counter) msg.flags |= defwinproc;
7674 if (beginpaint_counter) msg.flags |= beginpaint;
7675 msg.wParam = wParam;
7676 msg.lParam = lParam;
7677 msg.descr = "MsgCheckProc";
7678 add_message(&msg);
7679
7680 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7681 {
7682 HWND parent = GetParent(hwnd);
7683 RECT rc;
7684 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7685
7686 GetClientRect(parent, &rc);
7687 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7688 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7689 minmax->ptReserved.x, minmax->ptReserved.y,
7690 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7691 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7692 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7693 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7694
7695 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7696 minmax->ptMaxSize.x, rc.right);
7697 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7698 minmax->ptMaxSize.y, rc.bottom);
7699 }
7700
7701 if (message == WM_PAINT)
7702 {
7703 PAINTSTRUCT ps;
7704 beginpaint_counter++;
7705 BeginPaint( hwnd, &ps );
7706 beginpaint_counter--;
7707 EndPaint( hwnd, &ps );
7708 return 0;
7709 }
7710
7711 defwndproc_counter++;
7712 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
7713 : DefWindowProcA(hwnd, message, wParam, lParam);
7714 defwndproc_counter--;
7715
7716 return ret;
7717 }
7718
7719 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7720 {
7721 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7722 }
7723
7724 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7725 {
7726 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7727 }
7728
7729 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7730 {
7731 static LONG defwndproc_counter = 0;
7732 LRESULT ret;
7733 struct recvd_message msg;
7734
7735 if (ignore_message( message )) return 0;
7736
7737 switch (message)
7738 {
7739 case WM_QUERYENDSESSION:
7740 case WM_ENDSESSION:
7741 lParam &= ~0x01; /* Vista adds a 0x01 flag */
7742 break;
7743 }
7744
7745 msg.hwnd = hwnd;
7746 msg.message = message;
7747 msg.flags = sent|wparam|lparam;
7748 if (defwndproc_counter) msg.flags |= defwinproc;
7749 msg.wParam = wParam;
7750 msg.lParam = lParam;
7751 msg.descr = "popup";
7752 add_message(&msg);
7753
7754 if (message == WM_CREATE)
7755 {
7756 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7757 SetWindowLongA(hwnd, GWL_STYLE, style);
7758 }
7759
7760 defwndproc_counter++;
7761 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7762 defwndproc_counter--;
7763
7764 return ret;
7765 }
7766
7767 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7768 {
7769 static LONG defwndproc_counter = 0;
7770 static LONG beginpaint_counter = 0;
7771 LRESULT ret;
7772 struct recvd_message msg;
7773
7774 if (ignore_message( message )) return 0;
7775
7776 if (log_all_parent_messages ||
7777 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7778 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7779 message == WM_ENABLE || message == WM_ENTERIDLE ||
7780 message == WM_DRAWITEM || message == WM_COMMAND ||
7781 message == WM_IME_SETCONTEXT)
7782 {
7783 switch (message)
7784 {
7785 /* ignore */
7786 case WM_NCHITTEST:
7787 return HTCLIENT;
7788 case WM_SETCURSOR:
7789 case WM_MOUSEMOVE:
7790 case WM_NCMOUSEMOVE:
7791 return 0;
7792
7793 case WM_ERASEBKGND:
7794 {
7795 RECT rc;
7796 INT ret = GetClipBox((HDC)wParam, &rc);
7797
7798 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7799 ret, rc.left, rc.top, rc.right, rc.bottom);
7800 break;
7801 }
7802 }
7803
7804 msg.hwnd = hwnd;
7805 msg.message = message;
7806 msg.flags = sent|parent|wparam|lparam;
7807 if (defwndproc_counter) msg.flags |= defwinproc;
7808 if (beginpaint_counter) msg.flags |= beginpaint;
7809 msg.wParam = wParam;
7810 msg.lParam = lParam;
7811 msg.descr = "parent";
7812 add_message(&msg);
7813 }
7814
7815 if (message == WM_PAINT)
7816 {
7817 PAINTSTRUCT ps;
7818 beginpaint_counter++;
7819 BeginPaint( hwnd, &ps );
7820 beginpaint_counter--;
7821 EndPaint( hwnd, &ps );
7822 return 0;
7823 }
7824
7825 defwndproc_counter++;
7826 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7827 defwndproc_counter--;
7828
7829 return ret;
7830 }
7831
7832 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
7833 {
7834 if (message == WM_CREATE)
7835 PostMessageA(hwnd, WM_CLOSE, 0, 0);
7836 else if (message == WM_CLOSE)
7837 {
7838 /* Only the first WM_QUIT will survive the window destruction */
7839 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
7840 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
7841 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
7842 }
7843
7844 return DefWindowProcA(hwnd, message, wp, lp);
7845 }
7846
7847 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7848 {
7849 static LONG defwndproc_counter = 0;
7850 LRESULT ret;
7851 struct recvd_message msg;
7852
7853 if (ignore_message( message )) return 0;
7854
7855 if (test_def_id)
7856 {
7857 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7858 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7859 if (after_end_dialog)
7860 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7861 else
7862 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7863 }
7864
7865 msg.hwnd = hwnd;
7866 msg.message = message;
7867 msg.flags = sent|wparam|lparam;
7868 if (defwndproc_counter) msg.flags |= defwinproc;
7869 msg.wParam = wParam;
7870 msg.lParam = lParam;
7871 msg.descr = "dialog";
7872 add_message(&msg);
7873
7874 defwndproc_counter++;
7875 ret = DefDlgProcA(hwnd, message, wParam, lParam);
7876 defwndproc_counter--;
7877
7878 return ret;
7879 }
7880
7881 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7882 {
7883 static LONG defwndproc_counter = 0;
7884 LRESULT ret;
7885 struct recvd_message msg;
7886
7887 /* log only specific messages we are interested in */
7888 switch (message)
7889 {
7890 #if 0 /* probably log these as well */
7891 case WM_ACTIVATE:
7892 case WM_SETFOCUS:
7893 case WM_KILLFOCUS:
7894 #endif
7895 case WM_SHOWWINDOW:
7896 case WM_SIZE:
7897 case WM_MOVE:
7898 case WM_GETMINMAXINFO:
7899 case WM_WINDOWPOSCHANGING:
7900 case WM_WINDOWPOSCHANGED:
7901 break;
7902
7903 default: /* ignore */
7904 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7905 return DefWindowProcA(hwnd, message, wParam, lParam);
7906 }
7907
7908 msg.hwnd = hwnd;
7909 msg.message = message;
7910 msg.flags = sent|wparam|lparam;
7911 if (defwndproc_counter) msg.flags |= defwinproc;
7912 msg.wParam = wParam;
7913 msg.lParam = lParam;
7914 msg.descr = "show";
7915 add_message(&msg);
7916
7917 defwndproc_counter++;
7918 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7919 defwndproc_counter--;
7920
7921 return ret;
7922 }
7923
7924 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7925 {
7926 switch (msg)
7927 {
7928 case WM_CREATE: return 0;
7929 case WM_PAINT:
7930 {
7931 MSG msg2;
7932 static int i = 0;
7933
7934 if (i < 256)
7935 {
7936 i++;
7937 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7938 {
7939 TranslateMessage(&msg2);
7940 DispatchMessageA(&msg2);
7941 }
7942 i--;
7943 }
7944 else ok(broken(1), "infinite loop\n");
7945 if ( i == 0)
7946 paint_loop_done = TRUE;
7947 return DefWindowProcA(hWnd,msg,wParam,lParam);
7948 }
7949 }
7950 return DefWindowProcA(hWnd,msg,wParam,lParam);
7951 }
7952
7953 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7954 {
7955 static LONG defwndproc_counter = 0;
7956 LRESULT ret;
7957 struct recvd_message msg;
7958 DWORD queue_status;
7959
7960 if (ignore_message( message )) return 0;
7961
7962 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
7963 message == WM_HOTKEY || message >= WM_APP)
7964 {
7965 msg.hwnd = hwnd;
7966 msg.message = message;
7967 msg.flags = sent|wparam|lparam;
7968 if (defwndproc_counter) msg.flags |= defwinproc;
7969 msg.wParam = wParam;
7970 msg.lParam = lParam;
7971 msg.descr = "HotkeyMsgCheckProcA";
7972 add_message(&msg);
7973 }
7974
7975 defwndproc_counter++;
7976 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7977 defwndproc_counter--;
7978
7979 if (message == WM_APP)
7980 {
7981 queue_status = GetQueueStatus(QS_HOTKEY);
7982 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
7983 queue_status = GetQueueStatus(QS_POSTMESSAGE);
7984 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
7985 PostMessageA(hwnd, WM_APP+1, 0, 0);
7986 }
7987 else if (message == WM_APP+1)
7988 {
7989 queue_status = GetQueueStatus(QS_HOTKEY);
7990 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
7991 }
7992
7993 return ret;
7994 }
7995
7996 static BOOL RegisterWindowClasses(void)
7997 {
7998 WNDCLASSA cls;
7999 WNDCLASSW clsW;
8000
8001 cls.style = 0;
8002 cls.lpfnWndProc = MsgCheckProcA;
8003 cls.cbClsExtra = 0;
8004 cls.cbWndExtra = 0;
8005 cls.hInstance = GetModuleHandleA(0);
8006 cls.hIcon = 0;
8007 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
8008 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
8009 cls.lpszMenuName = NULL;
8010 cls.lpszClassName = "TestWindowClass";
8011 if(!RegisterClassA(&cls)) return FALSE;
8012
8013 cls.lpfnWndProc = HotkeyMsgCheckProcA;
8014 cls.lpszClassName = "HotkeyWindowClass";
8015 if(!RegisterClassA(&cls)) return FALSE;
8016
8017 cls.lpfnWndProc = ShowWindowProcA;
8018 cls.lpszClassName = "ShowWindowClass";
8019 if(!RegisterClassA(&cls)) return FALSE;
8020
8021 cls.lpfnWndProc = PopupMsgCheckProcA;
8022 cls.lpszClassName = "TestPopupClass";
8023 if(!RegisterClassA(&cls)) return FALSE;
8024
8025 cls.lpfnWndProc = ParentMsgCheckProcA;
8026 cls.lpszClassName = "TestParentClass";
8027 if(!RegisterClassA(&cls)) return FALSE;
8028
8029 cls.lpfnWndProc = StopQuitMsgCheckProcA;
8030 cls.lpszClassName = "StopQuitClass";
8031 if(!RegisterClassA(&cls)) return FALSE;
8032
8033 cls.lpfnWndProc = DefWindowProcA;
8034 cls.lpszClassName = "SimpleWindowClass";
8035 if(!RegisterClassA(&cls)) return FALSE;
8036
8037 cls.lpfnWndProc = PaintLoopProcA;
8038 cls.lpszClassName = "PaintLoopWindowClass";
8039 if(!RegisterClassA(&cls)) return FALSE;
8040
8041 cls.style = CS_NOCLOSE;
8042 cls.lpszClassName = "NoCloseWindowClass";
8043 if(!RegisterClassA(&cls)) return FALSE;
8044
8045 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
8046 cls.style = 0;
8047 cls.hInstance = GetModuleHandleA(0);
8048 cls.hbrBackground = 0;
8049 cls.lpfnWndProc = TestDlgProcA;
8050 cls.lpszClassName = "TestDialogClass";
8051 if(!RegisterClassA(&cls)) return FALSE;
8052
8053 clsW.style = 0;
8054 clsW.lpfnWndProc = MsgCheckProcW;
8055 clsW.cbClsExtra = 0;
8056 clsW.cbWndExtra = 0;
8057 clsW.hInstance = GetModuleHandleW(0);
8058 clsW.hIcon = 0;
8059 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
8060 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
8061 clsW.lpszMenuName = NULL;
8062 clsW.lpszClassName = testWindowClassW;
8063 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
8064
8065 return TRUE;
8066 }
8067
8068 static BOOL is_our_logged_class(HWND hwnd)
8069 {
8070 char buf[256];
8071
8072 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8073 {
8074 if (!lstrcmpiA(buf, "TestWindowClass") ||
8075 !lstrcmpiA(buf, "ShowWindowClass") ||
8076 !lstrcmpiA(buf, "TestParentClass") ||
8077 !lstrcmpiA(buf, "TestPopupClass") ||
8078 !lstrcmpiA(buf, "SimpleWindowClass") ||
8079 !lstrcmpiA(buf, "TestDialogClass") ||
8080 !lstrcmpiA(buf, "MDI_frame_class") ||
8081 !lstrcmpiA(buf, "MDI_client_class") ||
8082 !lstrcmpiA(buf, "MDI_child_class") ||
8083 !lstrcmpiA(buf, "my_button_class") ||
8084 !lstrcmpiA(buf, "my_edit_class") ||
8085 !lstrcmpiA(buf, "static") ||
8086 !lstrcmpiA(buf, "ListBox") ||
8087 !lstrcmpiA(buf, "ComboBox") ||
8088 !lstrcmpiA(buf, "MyDialogClass") ||
8089 !lstrcmpiA(buf, "#32770") ||
8090 !lstrcmpiA(buf, "#32768"))
8091 return TRUE;
8092 }
8093 return FALSE;
8094 }
8095
8096 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
8097 {
8098 HWND hwnd;
8099
8100 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
8101
8102 if (nCode == HCBT_CLICKSKIPPED)
8103 {
8104 /* ignore this event, XP sends it a lot when switching focus between windows */
8105 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8106 }
8107
8108 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
8109 {
8110 struct recvd_message msg;
8111
8112 msg.hwnd = 0;
8113 msg.message = nCode;
8114 msg.flags = hook|wparam|lparam;
8115 msg.wParam = wParam;
8116 msg.lParam = lParam;
8117 msg.descr = "CBT";
8118 add_message(&msg);
8119
8120 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8121 }
8122
8123 if (nCode == HCBT_DESTROYWND)
8124 {
8125 if (test_DestroyWindow_flag)
8126 {
8127 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
8128 if (style & WS_CHILD)
8129 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
8130 else if (style & WS_POPUP)
8131 lParam = WND_POPUP_ID;
8132 else
8133 lParam = WND_PARENT_ID;
8134 }
8135 }
8136
8137 /* Log also SetFocus(0) calls */
8138 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8139
8140 if (is_our_logged_class(hwnd))
8141 {
8142 struct recvd_message msg;
8143
8144 msg.hwnd = hwnd;
8145 msg.message = nCode;
8146 msg.flags = hook|wparam|lparam;
8147 msg.wParam = wParam;
8148 msg.lParam = lParam;
8149 msg.descr = "CBT";
8150 add_message(&msg);
8151 }
8152 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8153 }
8154
8155 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
8156 DWORD event,
8157 HWND hwnd,
8158 LONG object_id,
8159 LONG child_id,
8160 DWORD thread_id,
8161 DWORD event_time)
8162 {
8163 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
8164
8165 /* ignore mouse cursor events */
8166 if (object_id == OBJID_CURSOR) return;
8167
8168 if (!hwnd || is_our_logged_class(hwnd))
8169 {
8170 struct recvd_message msg;
8171
8172 msg.hwnd = hwnd;
8173 msg.message = event;
8174 msg.flags = winevent_hook|wparam|lparam;
8175 msg.wParam = object_id;
8176 msg.lParam = child_id;
8177 msg.descr = "WEH";
8178 add_message(&msg);
8179 }
8180 }
8181
8182 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
8183 static const WCHAR wszAnsi[] = {'U',0};
8184
8185 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
8186 {
8187 switch (uMsg)
8188 {
8189 case CB_FINDSTRINGEXACT:
8190 trace("String: %p\n", (LPCWSTR)lParam);
8191 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
8192 return 1;
8193 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
8194 return 0;
8195 return -1;
8196 }
8197 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
8198 }
8199
8200 static const struct message WmGetTextLengthAfromW[] = {
8201 { WM_GETTEXTLENGTH, sent },
8202 { WM_GETTEXT, sent|optional },
8203 { 0 }
8204 };
8205
8206 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
8207
8208 /* dummy window proc for WM_GETTEXTLENGTH test */
8209 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
8210 {
8211 switch(msg)
8212 {
8213 case WM_GETTEXTLENGTH:
8214 return lstrlenW(dummy_window_text) + 37; /* some random length */
8215 case WM_GETTEXT:
8216 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
8217 return lstrlenW( (LPWSTR)lp );
8218 default:
8219 return DefWindowProcW( hwnd, msg, wp, lp );
8220 }
8221 }
8222
8223 static void test_message_conversion(void)
8224 {
8225 static const WCHAR wszMsgConversionClass[] =
8226 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
8227 WNDCLASSW cls;
8228 LRESULT lRes;
8229 HWND hwnd;
8230 WNDPROC wndproc, newproc;
8231 BOOL ret;
8232
8233 cls.style = 0;
8234 cls.lpfnWndProc = MsgConversionProcW;
8235 cls.cbClsExtra = 0;
8236 cls.cbWndExtra = 0;
8237 cls.hInstance = GetModuleHandleW(NULL);
8238 cls.hIcon = NULL;
8239 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
8240 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
8241 cls.lpszMenuName = NULL;
8242 cls.lpszClassName = wszMsgConversionClass;
8243 /* this call will fail on Win9x, but that doesn't matter as this test is
8244 * meaningless on those platforms */
8245 if(!RegisterClassW(&cls)) return;
8246
8247 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
8248 100, 100, 200, 200, 0, 0, 0, NULL);
8249 ok(hwnd != NULL, "Window creation failed\n");
8250
8251 /* {W, A} -> A */
8252
8253 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
8254 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8255 ok(lRes == 0, "String should have been converted\n");
8256 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8257 ok(lRes == 1, "String shouldn't have been converted\n");
8258
8259 /* {W, A} -> W */
8260
8261 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
8262 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8263 ok(lRes == 1, "String shouldn't have been converted\n");
8264 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8265 ok(lRes == 1, "String shouldn't have been converted\n");
8266
8267 /* Synchronous messages */
8268
8269 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8270 ok(lRes == 0, "String should have been converted\n");
8271 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8272 ok(lRes == 1, "String shouldn't have been converted\n");
8273
8274 /* Asynchronous messages */
8275
8276 SetLastError(0);
8277 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8278 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8279 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8280 SetLastError(0);
8281 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8282 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8283 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8284 SetLastError(0);
8285 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8286 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8287 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8288 SetLastError(0);
8289 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8290 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8291 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8292 SetLastError(0);
8293 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8294 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8295 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8296 SetLastError(0);
8297 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8298 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8299 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8300 SetLastError(0);
8301 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8302 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8303 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8304 SetLastError(0);
8305 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8306 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8307 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8308
8309 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
8310
8311 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
8312 WS_OVERLAPPEDWINDOW,
8313 100, 100, 200, 200, 0, 0, 0, NULL);
8314 assert(hwnd);
8315 flush_sequence();
8316 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
8317 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8318 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8319 "got bad length %ld\n", lRes );
8320
8321 flush_sequence();
8322 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
8323 hwnd, WM_GETTEXTLENGTH, 0, 0);
8324 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8325 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8326 "got bad length %ld\n", lRes );
8327
8328 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
8329 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
8330 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8331 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8332 NULL, 0, NULL, NULL ) ||
8333 broken(lRes == lstrlenW(dummy_window_text) + 37),
8334 "got bad length %ld\n", lRes );
8335
8336 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
8337 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8338 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8339 NULL, 0, NULL, NULL ) ||
8340 broken(lRes == lstrlenW(dummy_window_text) + 37),
8341 "got bad length %ld\n", lRes );
8342
8343 ret = DestroyWindow(hwnd);
8344 ok( ret, "DestroyWindow() error %d\n", GetLastError());
8345 }
8346
8347 struct timer_info
8348 {
8349 HWND hWnd;
8350 HANDLE handles[2];
8351 DWORD id;
8352 };
8353
8354 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8355 {
8356 }
8357
8358 #define TIMER_ID 0x19
8359 #define TIMER_COUNT_EXPECTED 64
8360 #define TIMER_COUNT_TOLERANCE 9
8361
8362 static int count = 0;
8363 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
8364 {
8365 count++;
8366 }
8367
8368 static DWORD WINAPI timer_thread_proc(LPVOID x)
8369 {
8370 struct timer_info *info = x;
8371 DWORD r;
8372
8373 r = KillTimer(info->hWnd, 0x19);
8374 ok(r,"KillTimer failed in thread\n");
8375 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
8376 ok(r,"SetTimer failed in thread\n");
8377 ok(r==TIMER_ID,"SetTimer id different\n");
8378 r = SetEvent(info->handles[0]);
8379 ok(r,"SetEvent failed in thread\n");
8380 return 0;
8381 }
8382
8383 static void test_timers(void)
8384 {
8385 struct timer_info info;
8386 DWORD start;
8387 DWORD id;
8388 MSG msg;
8389
8390 info.hWnd = CreateWindowA("TestWindowClass", NULL,
8391 WS_OVERLAPPEDWINDOW ,
8392 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8393 NULL, NULL, 0);
8394
8395 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
8396 ok(info.id, "SetTimer failed\n");
8397 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
8398 info.handles[0] = CreateEventW(NULL,0,0,NULL);
8399 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
8400
8401 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
8402
8403 WaitForSingleObject(info.handles[1], INFINITE);
8404
8405 CloseHandle(info.handles[0]);
8406 CloseHandle(info.handles[1]);
8407
8408 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
8409
8410 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
8411 * but testing indicates that the minimum timeout is actually about 15.6 ms. Since there is
8412 * some measurement error between test runs we're allowing for ±8 counts (~2 ms).
8413 */
8414 count = 0;
8415 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
8416 ok(id != 0, "did not get id from SetTimer.\n");
8417 ok(id==TIMER_ID, "SetTimer timer ID different\n");
8418 start = GetTickCount();
8419 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
8420 DispatchMessageA(&msg);
8421 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
8422 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3 */,
8423 "did not get expected count for minimum timeout (%d != ~%d).\n",
8424 count, TIMER_COUNT_EXPECTED);
8425 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
8426 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
8427 if (pSetSystemTimer)
8428 {
8429 int syscount = 0;
8430
8431 count = 0;
8432 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
8433 ok(id != 0, "did not get id from SetSystemTimer.\n");
8434 ok(id==TIMER_ID, "SetTimer timer ID different\n");
8435 start = GetTickCount();
8436 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
8437 {
8438 if (msg.message == WM_SYSTIMER)
8439 syscount++;
8440 DispatchMessageA(&msg);
8441 }
8442 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE,
8443 "did not get expected count for minimum timeout (%d != ~%d).\n",
8444 syscount, TIMER_COUNT_EXPECTED);
8445 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
8446 count);
8447 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
8448 }
8449
8450 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8451 }
8452
8453 static void test_timers_no_wnd(void)
8454 {
8455 UINT_PTR id, id2;
8456 DWORD start;
8457 MSG msg;
8458
8459 count = 0;
8460 id = SetTimer(NULL, 0, 100, callback_count);
8461 ok(id != 0, "did not get id from SetTimer.\n");
8462 id2 = SetTimer(NULL, id, 200, callback_count);
8463 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
8464 Sleep(150);
8465 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8466 ok(count == 0, "did not get zero count as expected (%i).\n", count);
8467 Sleep(150);
8468 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8469 ok(count == 1, "did not get one count as expected (%i).\n", count);
8470 KillTimer(NULL, id);
8471 Sleep(250);
8472 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8473 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
8474
8475 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
8476 * but testing indicates that the minimum timeout is actually about 15.6 ms. Since there is
8477 * some measurement error between test runs we're allowing for ±8 counts (~2 ms).
8478 */
8479 count = 0;
8480 id = SetTimer(NULL, 0, 0, callback_count);
8481 ok(id != 0, "did not get id from SetTimer.\n");
8482 start = GetTickCount();
8483 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
8484 DispatchMessageA(&msg);
8485 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE,
8486 "did not get expected count for minimum timeout (%d != ~%d).\n",
8487 count, TIMER_COUNT_EXPECTED);
8488 KillTimer(NULL, id);
8489 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
8490 }
8491
8492 /* Various win events with arbitrary parameters */
8493 static const struct message WmWinEventsSeq[] = {
8494 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8495 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8496 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8497 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8498 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8499 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8500 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8501 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8502 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8503 /* our win event hook ignores OBJID_CURSOR events */
8504 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
8505 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
8506 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
8507 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
8508 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
8509 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8510 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8511 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8512 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8513 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8514 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8515 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8516 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8517 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8518 { 0 }
8519 };
8520 static const struct message WmWinEventCaretSeq[] = {
8521 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8522 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8523 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
8524 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8525 { 0 }
8526 };
8527 static const struct message WmWinEventCaretSeq_2[] = {
8528 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8529 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8530 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8531 { 0 }
8532 };
8533 static const struct message WmWinEventAlertSeq[] = {
8534 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
8535 { 0 }
8536 };
8537 static const struct message WmWinEventAlertSeq_2[] = {
8538 /* create window in the thread proc */
8539 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
8540 /* our test event */
8541 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
8542 { 0 }
8543 };
8544 static const struct message WmGlobalHookSeq_1[] = {
8545 /* create window in the thread proc */
8546 { HCBT_CREATEWND, hook|lparam, 0, 2 },
8547 /* our test events */
8548 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
8549 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
8550 { 0 }
8551 };
8552 static const struct message WmGlobalHookSeq_2[] = {
8553 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
8554 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
8555 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
8556 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
8557 { 0 }
8558 };
8559
8560 static const struct message WmMouseLLHookSeq[] = {
8561 { WM_MOUSEMOVE, hook },
8562 { WM_LBUTTONUP, hook },
8563 { WM_MOUSEMOVE, hook },
8564 { 0 }
8565 };
8566
8567 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
8568 DWORD event,
8569 HWND hwnd,
8570 LONG object_id,
8571 LONG child_id,
8572 DWORD thread_id,
8573 DWORD event_time)
8574 {
8575 char buf[256];
8576
8577 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8578 {
8579 if (!lstrcmpiA(buf, "TestWindowClass") ||
8580 !lstrcmpiA(buf, "static"))
8581 {
8582 struct recvd_message msg;
8583
8584 msg.hwnd = hwnd;
8585 msg.message = event;
8586 msg.flags = winevent_hook|wparam|lparam;
8587 msg.wParam = object_id;
8588 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8589 msg.descr = "WEH_2";
8590 add_message(&msg);
8591 }
8592 }
8593 }
8594
8595 static HHOOK hCBT_global_hook;
8596 static DWORD cbt_global_hook_thread_id;
8597
8598 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
8599 {
8600 HWND hwnd;
8601 char buf[256];
8602
8603 if (nCode == HCBT_SYSCOMMAND)
8604 {
8605 struct recvd_message msg;
8606
8607 msg.hwnd = 0;
8608 msg.message = nCode;
8609 msg.flags = hook|wparam|lparam;
8610 msg.wParam = wParam;
8611 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8612 msg.descr = "CBT_2";
8613 add_message(&msg);
8614
8615 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8616 }
8617 /* WH_MOUSE_LL hook */
8618 if (nCode == HC_ACTION)
8619 {
8620 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8621
8622 /* we can't test for real mouse events */
8623 if (mhll->flags & LLMHF_INJECTED)
8624 {
8625 struct recvd_message msg;
8626
8627 memset (&msg, 0, sizeof (msg));
8628 msg.message = wParam;
8629 msg.flags = hook;
8630 msg.descr = "CBT_2";
8631 add_message(&msg);
8632 }
8633 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8634 }
8635
8636 /* Log also SetFocus(0) calls */
8637 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8638
8639 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8640 {
8641 if (!lstrcmpiA(buf, "TestWindowClass") ||
8642 !lstrcmpiA(buf, "static"))
8643 {
8644 struct recvd_message msg;
8645
8646 msg.hwnd = hwnd;
8647 msg.message = nCode;
8648 msg.flags = hook|wparam|lparam;
8649 msg.wParam = wParam;
8650 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8651 msg.descr = "CBT_2";
8652 add_message(&msg);
8653 }
8654 }
8655 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8656 }
8657
8658 static DWORD WINAPI win_event_global_thread_proc(void *param)
8659 {
8660 HWND hwnd;
8661 MSG msg;
8662 HANDLE hevent = *(HANDLE *)param;
8663
8664 assert(pNotifyWinEvent);
8665
8666 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8667 assert(hwnd);
8668 trace("created thread window %p\n", hwnd);
8669
8670 *(HWND *)param = hwnd;
8671
8672 flush_sequence();
8673 /* this event should be received only by our new hook proc,
8674 * an old one does not expect an event from another thread.
8675 */
8676 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8677 SetEvent(hevent);
8678
8679 while (GetMessageA(&msg, 0, 0, 0))
8680 {
8681 TranslateMessage(&msg);
8682 DispatchMessageA(&msg);
8683 }
8684 return 0;
8685 }
8686
8687 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8688 {
8689 HWND hwnd;
8690 MSG msg;
8691 HANDLE hevent = *(HANDLE *)param;
8692
8693 flush_sequence();
8694 /* these events should be received only by our new hook proc,
8695 * an old one does not expect an event from another thread.
8696 */
8697
8698 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8699 assert(hwnd);
8700 trace("created thread window %p\n", hwnd);
8701
8702 *(HWND *)param = hwnd;
8703
8704 /* Windows doesn't like when a thread plays games with the focus,
8705 that leads to all kinds of misbehaviours and failures to activate
8706 a window. So, better keep next lines commented out.
8707 SetFocus(0);
8708 SetFocus(hwnd);*/
8709
8710 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8711 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8712
8713 SetEvent(hevent);
8714
8715 while (GetMessageA(&msg, 0, 0, 0))
8716 {
8717 TranslateMessage(&msg);
8718 DispatchMessageA(&msg);
8719 }
8720 return 0;
8721 }
8722
8723 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8724 {
8725 HWND hwnd;
8726 MSG msg;
8727 HANDLE hevent = *(HANDLE *)param;
8728
8729 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8730 assert(hwnd);
8731 trace("created thread window %p\n", hwnd);
8732
8733 *(HWND *)param = hwnd;
8734
8735 flush_sequence();
8736
8737 /* Windows doesn't like when a thread plays games with the focus,
8738 * that leads to all kinds of misbehaviours and failures to activate
8739 * a window. So, better don't generate a mouse click message below.
8740 */
8741 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8742 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8743 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8744
8745 SetEvent(hevent);
8746 while (GetMessageA(&msg, 0, 0, 0))
8747 {
8748 TranslateMessage(&msg);
8749 DispatchMessageA(&msg);
8750 }
8751 return 0;
8752 }
8753
8754 static void test_winevents(void)
8755 {
8756 BOOL ret;
8757 MSG msg;
8758 HWND hwnd, hwnd2;
8759 UINT i;
8760 HANDLE hthread, hevent;
8761 DWORD tid;
8762 HWINEVENTHOOK hhook;
8763 const struct message *events = WmWinEventsSeq;
8764
8765 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8766 WS_OVERLAPPEDWINDOW,
8767 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8768 NULL, NULL, 0);
8769 assert(hwnd);
8770
8771 /****** start of global hook test *************/
8772 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8773 if (!hCBT_global_hook)
8774 {
8775 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8776 skip( "cannot set global hook\n" );
8777 return;
8778 }
8779
8780 hevent = CreateEventA(NULL, 0, 0, NULL);
8781 assert(hevent);
8782 hwnd2 = hevent;
8783
8784 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8785 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8786
8787 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8788
8789 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8790
8791 flush_sequence();
8792 /* this one should be received only by old hook proc */
8793 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8794 /* this one should be received only by old hook proc */
8795 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8796
8797 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8798
8799 ret = UnhookWindowsHookEx(hCBT_global_hook);
8800 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8801
8802 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8803 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8804 CloseHandle(hthread);
8805 CloseHandle(hevent);
8806 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8807 /****** end of global hook test *************/
8808
8809 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8810 {
8811 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8812 return;
8813 }
8814
8815 flush_sequence();
8816
8817 if (0)
8818 {
8819 /* this test doesn't pass under Win9x */
8820 /* win2k ignores events with hwnd == 0 */
8821 SetLastError(0xdeadbeef);
8822 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8823 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8824 GetLastError() == 0xdeadbeef, /* Win9x */
8825 "unexpected error %d\n", GetLastError());
8826 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8827 }
8828
8829 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8830 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8831
8832 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8833
8834 /****** start of event filtering test *************/
8835 hhook = pSetWinEventHook(
8836 EVENT_OBJECT_SHOW, /* 0x8002 */
8837 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8838 GetModuleHandleA(0), win_event_global_hook_proc,
8839 GetCurrentProcessId(), 0,
8840 WINEVENT_INCONTEXT);
8841 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8842
8843 hevent = CreateEventA(NULL, 0, 0, NULL);
8844 assert(hevent);
8845 hwnd2 = hevent;
8846
8847 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8848 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8849
8850 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8851
8852 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8853
8854 flush_sequence();
8855 /* this one should be received only by old hook proc */
8856 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8857 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8858 /* this one should be received only by old hook proc */
8859 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8860
8861 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8862
8863 ret = pUnhookWinEvent(hhook);
8864 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8865
8866 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8867 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8868 CloseHandle(hthread);
8869 CloseHandle(hevent);
8870 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8871 /****** end of event filtering test *************/
8872
8873 /****** start of out of context event test *************/
8874 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8875 win_event_global_hook_proc, GetCurrentProcessId(), 0,
8876 WINEVENT_OUTOFCONTEXT);
8877 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8878
8879 hevent = CreateEventA(NULL, 0, 0, NULL);
8880 assert(hevent);
8881 hwnd2 = hevent;
8882
8883 flush_sequence();
8884
8885 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8886 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8887
8888 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8889
8890 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8891 /* process pending winevent messages */
8892 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8893 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8894
8895 flush_sequence();
8896 /* this one should be received only by old hook proc */
8897 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8898 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8899 /* this one should be received only by old hook proc */
8900 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8901
8902 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8903 /* process pending winevent messages */
8904 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8905 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8906
8907 ret = pUnhookWinEvent(hhook);
8908 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8909
8910 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8911 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8912 CloseHandle(hthread);
8913 CloseHandle(hevent);
8914 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8915 /****** end of out of context event test *************/
8916
8917 /****** start of MOUSE_LL hook test *************/
8918 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8919 /* WH_MOUSE_LL is not supported on Win9x platforms */
8920 if (!hCBT_global_hook)
8921 {
8922 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8923 goto skip_mouse_ll_hook_test;
8924 }
8925
8926 hevent = CreateEventA(NULL, 0, 0, NULL);
8927 assert(hevent);
8928 hwnd2 = hevent;
8929
8930 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8931 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8932
8933 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8934 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8935
8936 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8937 flush_sequence();
8938
8939 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8940 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8941 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8942
8943 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8944
8945 ret = UnhookWindowsHookEx(hCBT_global_hook);
8946 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8947
8948 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8949 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8950 CloseHandle(hthread);
8951 CloseHandle(hevent);
8952 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8953 /****** end of MOUSE_LL hook test *************/
8954 skip_mouse_ll_hook_test:
8955
8956 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8957 }
8958
8959 static void test_set_hook(void)
8960 {
8961 BOOL ret;
8962 HHOOK hhook;
8963 HWINEVENTHOOK hwinevent_hook;
8964
8965 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8966 ok(hhook != 0, "local hook does not require hModule set to 0\n");
8967 UnhookWindowsHookEx(hhook);
8968
8969 if (0)
8970 {
8971 /* this test doesn't pass under Win9x: BUG! */
8972 SetLastError(0xdeadbeef);
8973 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8974 ok(!hhook, "global hook requires hModule != 0\n");
8975 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8976 }
8977
8978 SetLastError(0xdeadbeef);
8979 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8980 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8981 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8982 GetLastError() == 0xdeadbeef, /* Win9x */
8983 "unexpected error %d\n", GetLastError());
8984
8985 SetLastError(0xdeadbeef);
8986 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8987 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8988 GetLastError() == 0xdeadbeef, /* Win9x */
8989 "unexpected error %d\n", GetLastError());
8990
8991 if (!pSetWinEventHook || !pUnhookWinEvent) return;
8992
8993 /* even process local incontext hooks require hmodule */
8994 SetLastError(0xdeadbeef);
8995 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8996 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8997 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8998 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8999 GetLastError() == 0xdeadbeef, /* Win9x */
9000 "unexpected error %d\n", GetLastError());
9001
9002 /* even thread local incontext hooks require hmodule */
9003 SetLastError(0xdeadbeef);
9004 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
9005 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
9006 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
9007 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
9008 GetLastError() == 0xdeadbeef, /* Win9x */
9009 "unexpected error %d\n", GetLastError());
9010
9011 if (0)
9012 {
9013 /* these 3 tests don't pass under Win9x */
9014 SetLastError(0xdeadbeef);
9015 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
9016 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
9017 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
9018 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
9019
9020 SetLastError(0xdeadbeef);
9021 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
9022 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
9023 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
9024 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
9025
9026 SetLastError(0xdeadbeef);
9027 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
9028 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
9029 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
9030 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
9031 }
9032
9033 SetLastError(0xdeadbeef);
9034 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
9035 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
9036 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
9037 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
9038 ret = pUnhookWinEvent(hwinevent_hook);
9039 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9040
9041 todo_wine {
9042 /* This call succeeds under win2k SP4, but fails under Wine.
9043 Does win2k test/use passed process id? */
9044 SetLastError(0xdeadbeef);
9045 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
9046 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
9047 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
9048 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
9049 ret = pUnhookWinEvent(hwinevent_hook);
9050 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9051 }
9052
9053 SetLastError(0xdeadbeef);
9054 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
9055 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
9056 GetLastError() == 0xdeadbeef, /* Win9x */
9057 "unexpected error %d\n", GetLastError());
9058 }
9059
9060 static const struct message ScrollWindowPaint1[] = {
9061 { WM_PAINT, sent },
9062 { WM_ERASEBKGND, sent|beginpaint },
9063 { WM_GETTEXTLENGTH, sent|optional },
9064 { WM_PAINT, sent|optional },
9065 { WM_NCPAINT, sent|beginpaint|optional },
9066 { WM_GETTEXT, sent|beginpaint|optional },
9067 { WM_GETTEXT, sent|beginpaint|optional },
9068 { WM_GETTEXT, sent|beginpaint|optional },
9069 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
9070 { WM_ERASEBKGND, sent|beginpaint|optional },
9071 { 0 }
9072 };
9073
9074 static const struct message ScrollWindowPaint2[] = {
9075 { WM_PAINT, sent },
9076 { 0 }
9077 };
9078
9079 static void test_scrollwindowex(void)
9080 {
9081 HWND hwnd, hchild;
9082 RECT rect={0,0,130,130};
9083
9084 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
9085 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
9086 100, 100, 200, 200, 0, 0, 0, NULL);
9087 ok (hwnd != 0, "Failed to create overlapped window\n");
9088 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
9089 WS_VISIBLE|WS_CAPTION|WS_CHILD,
9090 10, 10, 150, 150, hwnd, 0, 0, NULL);
9091 ok (hchild != 0, "Failed to create child\n");
9092 UpdateWindow(hwnd);
9093 flush_events();
9094 flush_sequence();
9095
9096 /* scroll without the child window */
9097 trace("start scroll\n");
9098 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
9099 SW_ERASE|SW_INVALIDATE);
9100 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
9101 trace("end scroll\n");
9102 flush_sequence();
9103 flush_events();
9104 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
9105 flush_events();
9106 flush_sequence();
9107
9108 /* Now without the SW_ERASE flag */
9109 trace("start scroll\n");
9110 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
9111 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
9112 trace("end scroll\n");
9113 flush_sequence();
9114 flush_events();
9115 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
9116 flush_events();
9117 flush_sequence();
9118
9119 /* now scroll the child window as well */
9120 trace("start scroll\n");
9121 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
9122 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
9123 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
9124 /* windows sometimes a WM_MOVE */
9125 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
9126 trace("end scroll\n");
9127 flush_sequence();
9128 flush_events();
9129 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
9130 flush_events();
9131 flush_sequence();
9132
9133 /* now scroll with ScrollWindow() */
9134 trace("start scroll with ScrollWindow\n");
9135 ScrollWindow( hwnd, 5, 5, NULL, NULL);
9136 trace("end scroll\n");
9137 flush_sequence();
9138 flush_events();
9139 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
9140
9141 ok(DestroyWindow(hchild), "failed to destroy window\n");
9142 ok(DestroyWindow(hwnd), "failed to destroy window\n");
9143 flush_sequence();
9144 }
9145
9146 static const struct message destroy_window_with_children[] = {
9147 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
9148 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
9149 { 0x0090, sent|optional },
9150 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
9151 { 0x0090, sent|optional },
9152 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
9153 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9154 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9155 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9156 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
9157 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
9158 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
9159 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
9160 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
9161 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
9162 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
9163 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
9164 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
9165 { 0 }
9166 };
9167
9168 static void test_DestroyWindow(void)
9169 {
9170 BOOL ret;
9171 HWND parent, child1, child2, child3, child4, test;
9172 UINT_PTR child_id = WND_CHILD_ID + 1;
9173
9174 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9175 100, 100, 200, 200, 0, 0, 0, NULL);
9176 assert(parent != 0);
9177 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9178 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
9179 assert(child1 != 0);
9180 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9181 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
9182 assert(child2 != 0);
9183 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9184 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
9185 assert(child3 != 0);
9186 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
9187 0, 0, 50, 50, parent, 0, 0, NULL);
9188 assert(child4 != 0);
9189
9190 /* test owner/parent of child2 */
9191 test = GetParent(child2);
9192 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9193 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
9194 if(pGetAncestor) {
9195 test = pGetAncestor(child2, GA_PARENT);
9196 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9197 }
9198 test = GetWindow(child2, GW_OWNER);
9199 ok(!test, "wrong owner %p\n", test);
9200
9201 test = SetParent(child2, parent);
9202 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
9203
9204 /* test owner/parent of the parent */
9205 test = GetParent(parent);
9206 ok(!test, "wrong parent %p\n", test);
9207 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
9208 if(pGetAncestor) {
9209 test = pGetAncestor(parent, GA_PARENT);
9210 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9211 }
9212 test = GetWindow(parent, GW_OWNER);
9213 ok(!test, "wrong owner %p\n", test);
9214
9215 /* test owner/parent of child1 */
9216 test = GetParent(child1);
9217 ok(test == parent, "wrong parent %p\n", test);
9218 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
9219 if(pGetAncestor) {
9220 test = pGetAncestor(child1, GA_PARENT);
9221 ok(test == parent, "wrong parent %p\n", test);
9222 }
9223 test = GetWindow(child1, GW_OWNER);
9224 ok(!test, "wrong owner %p\n", test);
9225
9226 /* test owner/parent of child2 */
9227 test = GetParent(child2);
9228 ok(test == parent, "wrong parent %p\n", test);
9229 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
9230 if(pGetAncestor) {
9231 test = pGetAncestor(child2, GA_PARENT);
9232 ok(test == parent, "wrong parent %p\n", test);
9233 }
9234 test = GetWindow(child2, GW_OWNER);
9235 ok(!test, "wrong owner %p\n", test);
9236
9237 /* test owner/parent of child3 */
9238 test = GetParent(child3);
9239 ok(test == child1, "wrong parent %p\n", test);
9240 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
9241 if(pGetAncestor) {
9242 test = pGetAncestor(child3, GA_PARENT);
9243 ok(test == child1, "wrong parent %p\n", test);
9244 }
9245 test = GetWindow(child3, GW_OWNER);
9246 ok(!test, "wrong owner %p\n", test);
9247
9248 /* test owner/parent of child4 */
9249 test = GetParent(child4);
9250 ok(test == parent, "wrong parent %p\n", test);
9251 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
9252 if(pGetAncestor) {
9253 test = pGetAncestor(child4, GA_PARENT);
9254 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9255 }
9256 test = GetWindow(child4, GW_OWNER);
9257 ok(test == parent, "wrong owner %p\n", test);
9258
9259 flush_sequence();
9260
9261 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
9262 parent, child1, child2, child3, child4);
9263
9264 SetCapture(child4);
9265 test = GetCapture();
9266 ok(test == child4, "wrong capture window %p\n", test);
9267
9268 test_DestroyWindow_flag = TRUE;
9269 ret = DestroyWindow(parent);
9270 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9271 test_DestroyWindow_flag = FALSE;
9272 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
9273
9274 ok(!IsWindow(parent), "parent still exists\n");
9275 ok(!IsWindow(child1), "child1 still exists\n");
9276 ok(!IsWindow(child2), "child2 still exists\n");
9277 ok(!IsWindow(child3), "child3 still exists\n");
9278 ok(!IsWindow(child4), "child4 still exists\n");
9279
9280 test = GetCapture();
9281 ok(!test, "wrong capture window %p\n", test);
9282 }
9283
9284
9285 static const struct message WmDispatchPaint[] = {
9286 { WM_NCPAINT, sent },
9287 { WM_GETTEXT, sent|defwinproc|optional },
9288 { WM_GETTEXT, sent|defwinproc|optional },
9289 { WM_ERASEBKGND, sent },
9290 { 0 }
9291 };
9292
9293 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9294 {
9295 if (message == WM_PAINT) return 0;
9296 return MsgCheckProcA( hwnd, message, wParam, lParam );
9297 }
9298
9299 static void test_DispatchMessage(void)
9300 {
9301 RECT rect;
9302 MSG msg;
9303 int count;
9304 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9305 100, 100, 200, 200, 0, 0, 0, NULL);
9306 ShowWindow( hwnd, SW_SHOW );
9307 UpdateWindow( hwnd );
9308 flush_events();
9309 flush_sequence();
9310 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
9311
9312 SetRect( &rect, -5, -5, 5, 5 );
9313 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9314 count = 0;
9315 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9316 {
9317 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9318 else
9319 {
9320 flush_sequence();
9321 DispatchMessageA( &msg );
9322 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
9323 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9324 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
9325 if (++count > 10) break;
9326 }
9327 }
9328 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
9329
9330 trace("now without DispatchMessage\n");
9331 flush_sequence();
9332 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9333 count = 0;
9334 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9335 {
9336 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9337 else
9338 {
9339 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
9340 flush_sequence();
9341 /* this will send WM_NCCPAINT just like DispatchMessage does */
9342 GetUpdateRgn( hwnd, hrgn, TRUE );
9343 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9344 DeleteObject( hrgn );
9345 GetClientRect( hwnd, &rect );
9346 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
9347 ok( !count, "Got multiple WM_PAINTs\n" );
9348 if (++count > 10) break;
9349 }
9350 }
9351
9352 flush_sequence();
9353 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9354 count = 0;
9355 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9356 {
9357 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9358 else
9359 {
9360 HDC hdc;
9361
9362 flush_sequence();
9363 hdc = BeginPaint( hwnd, NULL );
9364 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
9365 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
9366 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9367 ok( !count, "Got multiple WM_PAINTs\n" );
9368 if (++count > 10) break;
9369 }
9370 }
9371 DestroyWindow(hwnd);
9372 }
9373
9374
9375 static const struct message WmUser[] = {
9376 { WM_USER, sent },
9377 { 0 }
9378 };
9379
9380 struct sendmsg_info
9381 {
9382 HWND hwnd;
9383 DWORD timeout;
9384 DWORD ret;
9385 };
9386
9387 static DWORD CALLBACK send_msg_thread( LPVOID arg )
9388 {
9389 struct sendmsg_info *info = arg;
9390 SetLastError( 0xdeadbeef );
9391 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
9392 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
9393 broken(GetLastError() == 0), /* win9x */
9394 "unexpected error %d\n", GetLastError());
9395 return 0;
9396 }
9397
9398 static void wait_for_thread( HANDLE thread )
9399 {
9400 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
9401 {
9402 MSG msg;
9403 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
9404 }
9405 }
9406
9407 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9408 {
9409 if (message == WM_USER) Sleep(200);
9410 return MsgCheckProcA( hwnd, message, wParam, lParam );
9411 }
9412
9413 static void test_SendMessageTimeout(void)
9414 {
9415 HANDLE thread;
9416 struct sendmsg_info info;
9417 DWORD tid;
9418 BOOL is_win9x;
9419
9420 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9421 100, 100, 200, 200, 0, 0, 0, NULL);
9422 flush_events();
9423 flush_sequence();
9424
9425 info.timeout = 1000;
9426 info.ret = 0xdeadbeef;
9427 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9428 wait_for_thread( thread );
9429 CloseHandle( thread );
9430 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9431 ok_sequence( WmUser, "WmUser", FALSE );
9432
9433 info.timeout = 1;
9434 info.ret = 0xdeadbeef;
9435 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9436 Sleep(100); /* SendMessageTimeout should time out here */
9437 wait_for_thread( thread );
9438 CloseHandle( thread );
9439 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9440 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9441
9442 /* 0 means infinite timeout (but not on win9x) */
9443 info.timeout = 0;
9444 info.ret = 0xdeadbeef;
9445 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9446 Sleep(100);
9447 wait_for_thread( thread );
9448 CloseHandle( thread );
9449 is_win9x = !info.ret;
9450 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9451 else ok_sequence( WmUser, "WmUser", FALSE );
9452
9453 /* timeout is treated as signed despite the prototype (but not on win9x) */
9454 info.timeout = 0x7fffffff;
9455 info.ret = 0xdeadbeef;
9456 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9457 Sleep(100);
9458 wait_for_thread( thread );
9459 CloseHandle( thread );
9460 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9461 ok_sequence( WmUser, "WmUser", FALSE );
9462
9463 info.timeout = 0x80000000;
9464 info.ret = 0xdeadbeef;
9465 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9466 Sleep(100);
9467 wait_for_thread( thread );
9468 CloseHandle( thread );
9469 if (is_win9x)
9470 {
9471 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9472 ok_sequence( WmUser, "WmUser", FALSE );
9473 }
9474 else
9475 {
9476 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9477 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9478 }
9479
9480 /* now check for timeout during message processing */
9481 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
9482 info.timeout = 100;
9483 info.ret = 0xdeadbeef;
9484 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9485 wait_for_thread( thread );
9486 CloseHandle( thread );
9487 /* we should time out but still get the message */
9488 ok( info.ret == 0, "SendMessageTimeout failed\n" );
9489 ok_sequence( WmUser, "WmUser", FALSE );
9490
9491 DestroyWindow( info.hwnd );
9492 }
9493
9494
9495 /****************** edit message test *************************/
9496 #define ID_EDIT 0x1234
9497 static const struct message sl_edit_setfocus[] =
9498 {
9499 { HCBT_SETFOCUS, hook },
9500 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9501 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9502 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9503 { WM_SETFOCUS, sent|wparam, 0 },
9504 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9505 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
9506 { WM_CTLCOLOREDIT, sent|parent },
9507 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9508 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9509 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9510 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9511 { 0 }
9512 };
9513 static const struct message sl_edit_invisible[] =
9514 {
9515 { HCBT_SETFOCUS, hook },
9516 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9517 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9518 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9519 { WM_KILLFOCUS, sent|parent },
9520 { WM_SETFOCUS, sent },
9521 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9522 { 0 }
9523 };
9524 static const struct message ml_edit_setfocus[] =
9525 {
9526 { HCBT_SETFOCUS, hook },
9527 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9528 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9529 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9530 { WM_SETFOCUS, sent|wparam, 0 },
9531 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9532 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9533 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9534 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9535 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9536 { 0 }
9537 };
9538 static const struct message sl_edit_killfocus[] =
9539 {
9540 { HCBT_SETFOCUS, hook },
9541 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9542 { WM_KILLFOCUS, sent|wparam, 0 },
9543 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9544 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9545 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
9546 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9547 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
9548 { 0 }
9549 };
9550 static const struct message sl_edit_lbutton_dblclk[] =
9551 {
9552 { WM_LBUTTONDBLCLK, sent },
9553 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9554 { 0 }
9555 };
9556 static const struct message sl_edit_lbutton_down[] =
9557 {
9558 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9559 { HCBT_SETFOCUS, hook },
9560 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9561 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9562 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9563 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9564 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9565 { WM_CTLCOLOREDIT, sent|parent },
9566 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9567 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9568 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9569 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9570 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9571 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9572 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9573 { WM_CTLCOLOREDIT, sent|parent|optional },
9574 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9575 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9576 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9577 { 0 }
9578 };
9579 static const struct message ml_edit_lbutton_down[] =
9580 {
9581 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9582 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9583 { HCBT_SETFOCUS, hook },
9584 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9585 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9586 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9587 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9588 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9589 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9590 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9591 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9592 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9593 { 0 }
9594 };
9595 static const struct message sl_edit_lbutton_up[] =
9596 {
9597 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9598 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9599 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9600 { WM_CAPTURECHANGED, sent|defwinproc },
9601 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9602 { 0 }
9603 };
9604 static const struct message ml_edit_lbutton_up[] =
9605 {
9606 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9607 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9608 { WM_CAPTURECHANGED, sent|defwinproc },
9609 { 0 }
9610 };
9611
9612 static WNDPROC old_edit_proc;
9613
9614 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9615 {
9616 static LONG defwndproc_counter = 0;
9617 LRESULT ret;
9618 struct recvd_message msg;
9619
9620 if (ignore_message( message )) return 0;
9621
9622 msg.hwnd = hwnd;
9623 msg.message = message;
9624 msg.flags = sent|wparam|lparam;
9625 if (defwndproc_counter) msg.flags |= defwinproc;
9626 msg.wParam = wParam;
9627 msg.lParam = lParam;
9628 msg.descr = "edit";
9629 add_message(&msg);
9630
9631 defwndproc_counter++;
9632 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9633 defwndproc_counter--;
9634
9635 return ret;
9636 }
9637
9638 static void subclass_edit(void)
9639 {
9640 WNDCLASSA cls;
9641
9642 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9643
9644 old_edit_proc = cls.lpfnWndProc;
9645
9646 cls.hInstance = GetModuleHandleA(NULL);
9647 cls.lpfnWndProc = edit_hook_proc;
9648 cls.lpszClassName = "my_edit_class";
9649 UnregisterClassA(cls.lpszClassName, cls.hInstance);
9650 if (!RegisterClassA(&cls)) assert(0);
9651 }
9652
9653 static void test_edit_messages(void)
9654 {
9655 HWND hwnd, parent;
9656 DWORD dlg_code;
9657
9658 subclass_edit();
9659 log_all_parent_messages++;
9660
9661 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9662 100, 100, 200, 200, 0, 0, 0, NULL);
9663 ok (parent != 0, "Failed to create parent window\n");
9664
9665 /* test single line edit */
9666 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9667 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9668 ok(hwnd != 0, "Failed to create edit window\n");
9669
9670 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9671 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9672
9673 flush_sequence();
9674 SetFocus(hwnd);
9675 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
9676
9677 ShowWindow(hwnd, SW_SHOW);
9678 UpdateWindow(hwnd);
9679 SetFocus(0);
9680 flush_sequence();
9681
9682 SetFocus(hwnd);
9683 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9684
9685 SetFocus(0);
9686 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9687
9688 SetFocus(0);
9689 ReleaseCapture();
9690 flush_sequence();
9691
9692 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9693 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9694
9695 SetFocus(0);
9696 ReleaseCapture();
9697 flush_sequence();
9698
9699 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9700 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9701
9702 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9703 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9704
9705 DestroyWindow(hwnd);
9706
9707 /* test multiline edit */
9708 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9709 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9710 ok(hwnd != 0, "Failed to create edit window\n");
9711
9712 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9713 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9714 "wrong dlg_code %08x\n", dlg_code);
9715
9716 ShowWindow(hwnd, SW_SHOW);
9717 UpdateWindow(hwnd);
9718 SetFocus(0);
9719 flush_sequence();
9720
9721 SetFocus(hwnd);
9722 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9723
9724 SetFocus(0);
9725 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9726
9727 SetFocus(0);
9728 ReleaseCapture();
9729 flush_sequence();
9730
9731 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9732 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9733
9734 SetFocus(0);
9735 ReleaseCapture();
9736 flush_sequence();
9737
9738 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9739 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9740
9741 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9742 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9743
9744 DestroyWindow(hwnd);
9745 DestroyWindow(parent);
9746
9747 log_all_parent_messages--;
9748 }
9749
9750 /**************************** End of Edit test ******************************/
9751
9752 static const struct message WmKeyDownSkippedSeq[] =
9753 {
9754 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9755 { 0 }
9756 };
9757 static const struct message WmKeyDownWasDownSkippedSeq[] =
9758 {
9759 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9760 { 0 }
9761 };
9762 static const struct message WmKeyUpSkippedSeq[] =
9763 {
9764 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9765 { 0 }
9766 };
9767 static const struct message WmUserKeyUpSkippedSeq[] =
9768 {
9769 { WM_USER, sent },
9770 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9771 { 0 }
9772 };
9773
9774 #define EV_STOP 0
9775 #define EV_SENDMSG 1
9776 #define EV_ACK 2
9777
9778 struct peekmsg_info
9779 {
9780 HWND hwnd;
9781 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9782 };
9783
9784 static DWORD CALLBACK send_msg_thread_2(void *param)
9785 {
9786 DWORD ret;
9787 struct peekmsg_info *info = param;
9788
9789 trace("thread: looping\n");
9790 SetEvent(info->hevent[EV_ACK]);
9791
9792 while (1)
9793 {
9794 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9795
9796 switch (ret)
9797 {
9798 case WAIT_OBJECT_0 + EV_STOP:
9799 trace("thread: exiting\n");
9800 return 0;
9801
9802 case WAIT_OBJECT_0 + EV_SENDMSG:
9803 trace("thread: sending message\n");
9804 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
9805 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
9806 SetEvent(info->hevent[EV_ACK]);
9807 break;
9808
9809 default:
9810 trace("unexpected return: %04x\n", ret);
9811 assert(0);
9812 break;
9813 }
9814 }
9815 return 0;
9816 }
9817
9818 static void test_PeekMessage(void)
9819 {
9820 MSG msg;
9821 HANDLE hthread;
9822 DWORD tid, qstatus;
9823 UINT qs_all_input = QS_ALLINPUT;
9824 UINT qs_input = QS_INPUT;
9825 BOOL ret;
9826 struct peekmsg_info info;
9827
9828 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9829 100, 100, 200, 200, 0, 0, 0, NULL);
9830 assert(info.hwnd);
9831 ShowWindow(info.hwnd, SW_SHOW);
9832 UpdateWindow(info.hwnd);
9833 SetFocus(info.hwnd);
9834
9835 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9836 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9837 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9838
9839 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9840 WaitForSingleObject(info.hevent[EV_ACK], 10000);
9841
9842 flush_events();
9843 flush_sequence();
9844
9845 SetLastError(0xdeadbeef);
9846 qstatus = GetQueueStatus(qs_all_input);
9847 if (GetLastError() == ERROR_INVALID_FLAGS)
9848 {
9849 trace("QS_RAWINPUT not supported on this platform\n");
9850 qs_all_input &= ~QS_RAWINPUT;
9851 qs_input &= ~QS_RAWINPUT;
9852 }
9853 if (qstatus & QS_POSTMESSAGE)
9854 {
9855 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9856 qstatus = GetQueueStatus(qs_all_input);
9857 }
9858 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9859
9860 trace("signalling to send message\n");
9861 SetEvent(info.hevent[EV_SENDMSG]);
9862 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9863
9864 /* pass invalid QS_xxxx flags */
9865 SetLastError(0xdeadbeef);
9866 qstatus = GetQueueStatus(0xffffffff);
9867 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9868 if (!qstatus)
9869 {
9870 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9871 qstatus = GetQueueStatus(qs_all_input);
9872 }
9873 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
9874 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9875 "wrong qstatus %08x\n", qstatus);
9876
9877 msg.message = 0;
9878 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9879 ok(!ret,
9880 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9881 msg.message);
9882 ok_sequence(WmUser, "WmUser", FALSE);
9883
9884 qstatus = GetQueueStatus(qs_all_input);
9885 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9886
9887 keybd_event('N', 0, 0, 0);
9888 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9889 qstatus = GetQueueStatus(qs_all_input);
9890 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9891 {
9892 skip( "queuing key events not supported\n" );
9893 goto done;
9894 }
9895 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
9896 /* keybd_event seems to trigger a sent message on NT4 */
9897 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
9898 "wrong qstatus %08x\n", qstatus);
9899
9900 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9901 qstatus = GetQueueStatus(qs_all_input);
9902 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
9903 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9904 "wrong qstatus %08x\n", qstatus);
9905
9906 InvalidateRect(info.hwnd, NULL, FALSE);
9907 qstatus = GetQueueStatus(qs_all_input);
9908 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
9909 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9910 "wrong qstatus %08x\n", qstatus);
9911
9912 trace("signalling to send message\n");
9913 SetEvent(info.hevent[EV_SENDMSG]);
9914 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9915
9916 qstatus = GetQueueStatus(qs_all_input);
9917 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9918 "wrong qstatus %08x\n", qstatus);
9919
9920 msg.message = 0;
9921 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9922 if (ret && msg.message == WM_CHAR)
9923 {
9924 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9925 goto done;
9926 }
9927 ok(!ret,
9928 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9929 msg.message);
9930 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
9931 {
9932 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9933 goto done;
9934 }
9935 ok_sequence(WmUser, "WmUser", FALSE);
9936
9937 qstatus = GetQueueStatus(qs_all_input);
9938 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9939 "wrong qstatus %08x\n", qstatus);
9940
9941 trace("signalling to send message\n");
9942 SetEvent(info.hevent[EV_SENDMSG]);
9943 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9944
9945 qstatus = GetQueueStatus(qs_all_input);
9946 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9947 "wrong qstatus %08x\n", qstatus);
9948
9949 msg.message = 0;
9950 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9951 ok(!ret,
9952 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9953 msg.message);
9954 ok_sequence(WmUser, "WmUser", FALSE);
9955
9956 qstatus = GetQueueStatus(qs_all_input);
9957 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9958 "wrong qstatus %08x\n", qstatus);
9959
9960 msg.message = 0;
9961 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9962 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9963 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9964 ret, msg.message, msg.wParam);
9965 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9966
9967 qstatus = GetQueueStatus(qs_all_input);
9968 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9969 "wrong qstatus %08x\n", qstatus);
9970
9971 msg.message = 0;
9972 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9973 ok(!ret,
9974 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9975 msg.message);
9976 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9977
9978 qstatus = GetQueueStatus(qs_all_input);
9979 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9980 "wrong qstatus %08x\n", qstatus);
9981
9982 msg.message = 0;
9983 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9984 ok(ret && msg.message == WM_PAINT,
9985 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9986 DispatchMessageA(&msg);
9987 ok_sequence(WmPaint, "WmPaint", FALSE);
9988
9989 qstatus = GetQueueStatus(qs_all_input);
9990 ok(qstatus == MAKELONG(0, QS_KEY),
9991 "wrong qstatus %08x\n", qstatus);
9992
9993 msg.message = 0;
9994 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9995 ok(!ret,
9996 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9997 msg.message);
9998 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9999
10000 qstatus = GetQueueStatus(qs_all_input);
10001 ok(qstatus == MAKELONG(0, QS_KEY),
10002 "wrong qstatus %08x\n", qstatus);
10003
10004 trace("signalling to send message\n");
10005 SetEvent(info.hevent[EV_SENDMSG]);
10006 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10007
10008 qstatus = GetQueueStatus(qs_all_input);
10009 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
10010 "wrong qstatus %08x\n", qstatus);
10011
10012 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10013
10014 qstatus = GetQueueStatus(qs_all_input);
10015 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
10016 "wrong qstatus %08x\n", qstatus);
10017
10018 msg.message = 0;
10019 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
10020 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10021 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10022 ret, msg.message, msg.wParam);
10023 ok_sequence(WmUser, "WmUser", FALSE);
10024
10025 qstatus = GetQueueStatus(qs_all_input);
10026 ok(qstatus == MAKELONG(0, QS_KEY),
10027 "wrong qstatus %08x\n", qstatus);
10028
10029 msg.message = 0;
10030 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
10031 ok(!ret,
10032 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10033 msg.message);
10034 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10035
10036 qstatus = GetQueueStatus(qs_all_input);
10037 ok(qstatus == MAKELONG(0, QS_KEY),
10038 "wrong qstatus %08x\n", qstatus);
10039
10040 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10041
10042 qstatus = GetQueueStatus(qs_all_input);
10043 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
10044 "wrong qstatus %08x\n", qstatus);
10045
10046 trace("signalling to send message\n");
10047 SetEvent(info.hevent[EV_SENDMSG]);
10048 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10049
10050 qstatus = GetQueueStatus(qs_all_input);
10051 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
10052 "wrong qstatus %08x\n", qstatus);
10053
10054 msg.message = 0;
10055 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
10056 ok(!ret,
10057 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10058 msg.message);
10059 ok_sequence(WmUser, "WmUser", FALSE);
10060
10061 qstatus = GetQueueStatus(qs_all_input);
10062 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
10063 "wrong qstatus %08x\n", qstatus);
10064
10065 msg.message = 0;
10066 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
10067 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
10068 else /* workaround for a missing QS_RAWINPUT support */
10069 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
10070 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10071 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10072 ret, msg.message, msg.wParam);
10073 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
10074
10075 qstatus = GetQueueStatus(qs_all_input);
10076 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
10077 "wrong qstatus %08x\n", qstatus);
10078
10079 msg.message = 0;
10080 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
10081 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
10082 else /* workaround for a missing QS_RAWINPUT support */
10083 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
10084 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
10085 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
10086 ret, msg.message, msg.wParam);
10087 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
10088
10089 qstatus = GetQueueStatus(qs_all_input);
10090 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10091 "wrong qstatus %08x\n", qstatus);
10092
10093 msg.message = 0;
10094 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
10095 ok(!ret,
10096 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10097 msg.message);
10098 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10099
10100 qstatus = GetQueueStatus(qs_all_input);
10101 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10102 "wrong qstatus %08x\n", qstatus);
10103
10104 msg.message = 0;
10105 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10106 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10107 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10108 ret, msg.message, msg.wParam);
10109 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10110
10111 qstatus = GetQueueStatus(qs_all_input);
10112 ok(qstatus == 0,
10113 "wrong qstatus %08x\n", qstatus);
10114
10115 msg.message = 0;
10116 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10117 ok(!ret,
10118 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10119 msg.message);
10120 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10121
10122 qstatus = GetQueueStatus(qs_all_input);
10123 ok(qstatus == 0,
10124 "wrong qstatus %08x\n", qstatus);
10125
10126 /* test whether presence of the quit flag in the queue affects
10127 * the queue state
10128 */
10129 PostQuitMessage(0x1234abcd);
10130
10131 qstatus = GetQueueStatus(qs_all_input);
10132 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
10133 "wrong qstatus %08x\n", qstatus);
10134
10135 PostMessageA(info.hwnd, WM_USER, 0, 0);
10136
10137 qstatus = GetQueueStatus(qs_all_input);
10138 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
10139 "wrong qstatus %08x\n", qstatus);
10140
10141 msg.message = 0;
10142 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10143 ok(ret && msg.message == WM_USER,
10144 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
10145 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10146
10147 qstatus = GetQueueStatus(qs_all_input);
10148 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10149 "wrong qstatus %08x\n", qstatus);
10150
10151 msg.message = 0;
10152 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10153 ok(ret && msg.message == WM_QUIT,
10154 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
10155 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
10156 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
10157 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10158
10159 qstatus = GetQueueStatus(qs_all_input);
10160 todo_wine {
10161 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10162 "wrong qstatus %08x\n", qstatus);
10163 }
10164
10165 msg.message = 0;
10166 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10167 ok(!ret,
10168 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10169 msg.message);
10170 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10171
10172 qstatus = GetQueueStatus(qs_all_input);
10173 ok(qstatus == 0,
10174 "wrong qstatus %08x\n", qstatus);
10175
10176 /* some GetMessage tests */
10177
10178 keybd_event('N', 0, 0, 0);
10179 qstatus = GetQueueStatus(qs_all_input);
10180 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10181
10182 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10183 qstatus = GetQueueStatus(qs_all_input);
10184 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10185
10186 if (qstatus)
10187 {
10188 ret = GetMessageA( &msg, 0, 0, 0 );
10189 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10190 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10191 ret, msg.message, msg.wParam);
10192 qstatus = GetQueueStatus(qs_all_input);
10193 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
10194 }
10195
10196 if (qstatus)
10197 {
10198 ret = GetMessageA( &msg, 0, 0, 0 );
10199 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10200 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10201 ret, msg.message, msg.wParam);
10202 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
10203 qstatus = GetQueueStatus(qs_all_input);
10204 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10205 }
10206
10207 keybd_event('N', 0, 0, 0);
10208 qstatus = GetQueueStatus(qs_all_input);
10209 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10210
10211 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10212 qstatus = GetQueueStatus(qs_all_input);
10213 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10214
10215 if (qstatus & (QS_KEY << 16))
10216 {
10217 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
10218 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10219 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10220 ret, msg.message, msg.wParam);
10221 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
10222 qstatus = GetQueueStatus(qs_all_input);
10223 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
10224 }
10225
10226 if (qstatus)
10227 {
10228 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
10229 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10230 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10231 ret, msg.message, msg.wParam);
10232 qstatus = GetQueueStatus(qs_all_input);
10233 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10234 }
10235
10236 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10237 qstatus = GetQueueStatus(qs_all_input);
10238 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10239
10240 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10241 qstatus = GetQueueStatus(qs_all_input);
10242 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10243
10244 trace("signalling to send message\n");
10245 SetEvent(info.hevent[EV_SENDMSG]);
10246 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10247 qstatus = GetQueueStatus(qs_all_input);
10248 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
10249 "wrong qstatus %08x\n", qstatus);
10250
10251 if (qstatus & (QS_KEY << 16))
10252 {
10253 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
10254 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
10255 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10256 ret, msg.message, msg.wParam);
10257 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
10258 qstatus = GetQueueStatus(qs_all_input);
10259 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
10260 }
10261
10262 if (qstatus)
10263 {
10264 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
10265 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10266 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10267 ret, msg.message, msg.wParam);
10268 qstatus = GetQueueStatus(qs_all_input);
10269 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10270 }
10271 done:
10272 trace("signalling to exit\n");
10273 SetEvent(info.hevent[EV_STOP]);
10274
10275 WaitForSingleObject(hthread, INFINITE);
10276
10277 CloseHandle(hthread);
10278 CloseHandle(info.hevent[0]);
10279 CloseHandle(info.hevent[1]);
10280 CloseHandle(info.hevent[2]);
10281
10282 DestroyWindow(info.hwnd);
10283 }
10284
10285 static void wait_move_event(HWND hwnd, int x, int y)
10286 {
10287 MSG msg;
10288 DWORD time;
10289 BOOL ret, go = FALSE;
10290
10291 time = GetTickCount();
10292 while (GetTickCount() - time < 200 && !go) {
10293 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10294 go = ret && msg.pt.x > x && msg.pt.y > y;
10295 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
10296 }
10297 }
10298
10299 #define STEP 5
10300 static void test_PeekMessage2(void)
10301 {
10302 HWND hwnd;
10303 BOOL ret;
10304 MSG msg;
10305 UINT message;
10306 DWORD time1, time2, time3;
10307 int x1, y1, x2, y2, x3, y3;
10308 POINT pos;
10309
10310 time1 = time2 = time3 = 0;
10311 x1 = y1 = x2 = y2 = x3 = y3 = 0;
10312
10313 /* Initialise window and make sure it is ready for events */
10314 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
10315 10, 10, 800, 800, NULL, NULL, NULL, NULL);
10316 assert(hwnd);
10317 trace("Window for test_PeekMessage2 %p\n", hwnd);
10318 ShowWindow(hwnd, SW_SHOW);
10319 UpdateWindow(hwnd);
10320 SetFocus(hwnd);
10321 GetCursorPos(&pos);
10322 SetCursorPos(100, 100);
10323 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
10324 flush_events();
10325
10326 /* Do initial mousemove, wait until we can see it
10327 and then do our test peek with PM_NOREMOVE. */
10328 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10329 wait_move_event(hwnd, 100-STEP, 100-STEP);
10330
10331 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10332 if (!ret)
10333 {
10334 skip( "queuing mouse events not supported\n" );
10335 goto done;
10336 }
10337 else
10338 {
10339 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10340 message = msg.message;
10341 time1 = msg.time;
10342 x1 = msg.pt.x;
10343 y1 = msg.pt.y;
10344 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10345 }
10346
10347 /* Allow time to advance a bit, and then simulate the user moving their
10348 * mouse around. After that we peek again with PM_NOREMOVE.
10349 * Although the previous mousemove message was never removed, the
10350 * mousemove we now peek should reflect the recent mouse movements
10351 * because the input queue will merge the move events. */
10352 Sleep(100);
10353 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10354 wait_move_event(hwnd, x1, y1);
10355
10356 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10357 ok(ret, "no message available\n");
10358 if (ret) {
10359 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10360 message = msg.message;
10361 time2 = msg.time;
10362 x2 = msg.pt.x;
10363 y2 = msg.pt.y;
10364 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10365 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
10366 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
10367 }
10368
10369 /* Have another go, to drive the point home */
10370 Sleep(100);
10371 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10372 wait_move_event(hwnd, x2, y2);
10373
10374 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10375 ok(ret, "no message available\n");
10376 if (ret) {
10377 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10378 message = msg.message;
10379 time3 = msg.time;
10380 x3 = msg.pt.x;
10381 y3 = msg.pt.y;
10382 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10383 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
10384 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
10385 }
10386
10387 done:
10388 DestroyWindow(hwnd);
10389 SetCursorPos(pos.x, pos.y);
10390 flush_events();
10391 }
10392
10393 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10394 {
10395 struct recvd_message msg;
10396
10397 if (ignore_message( message )) return 0;
10398
10399 msg.hwnd = hwnd;
10400 msg.message = message;
10401 msg.flags = sent|wparam|lparam;
10402 msg.wParam = wp;
10403 msg.lParam = lp;
10404 msg.descr = "dialog";
10405 add_message(&msg);
10406
10407 switch (message)
10408 {
10409 case WM_INITDIALOG:
10410 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
10411 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
10412 return 0;
10413
10414 case WM_GETDLGCODE:
10415 return 0;
10416
10417 case WM_USER:
10418 EndDialog(hwnd, 0);
10419 break;
10420 }
10421
10422 return 1;
10423 }
10424
10425 static const struct message WmQuitDialogSeq[] = {
10426 { HCBT_CREATEWND, hook },
10427 { WM_SETFONT, sent },
10428 { WM_INITDIALOG, sent },
10429 { WM_CHANGEUISTATE, sent|optional },
10430 { HCBT_DESTROYWND, hook },
10431 { 0x0090, sent|optional }, /* Vista */
10432 { WM_DESTROY, sent },
10433 { WM_NCDESTROY, sent },
10434 { 0 }
10435 };
10436
10437 static const struct message WmStopQuitSeq[] = {
10438 { WM_DWMNCRENDERINGCHANGED, posted|optional },
10439 { WM_CLOSE, posted },
10440 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
10441 { 0 }
10442 };
10443
10444 static void test_quit_message(void)
10445 {
10446 MSG msg;
10447 BOOL ret;
10448
10449 /* test using PostQuitMessage */
10450 flush_events();
10451 PostQuitMessage(0xbeef);
10452
10453 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
10454 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10455 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10456 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10457
10458 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
10459 ok(ret, "PostMessage failed with error %d\n", GetLastError());
10460
10461 ret = GetMessageA(&msg, NULL, 0, 0);
10462 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10463 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10464
10465 /* note: WM_QUIT message received after WM_USER message */
10466 ret = GetMessageA(&msg, NULL, 0, 0);
10467 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10468 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10469 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10470
10471 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
10472 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
10473
10474 /* now test with PostThreadMessage - different behaviour! */
10475 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
10476
10477 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
10478 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10479 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10480 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10481
10482 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
10483 ok(ret, "PostMessage failed with error %d\n", GetLastError());
10484
10485 /* note: we receive the WM_QUIT message first this time */
10486 ret = GetMessageA(&msg, NULL, 0, 0);
10487 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10488 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10489 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10490
10491 ret = GetMessageA(&msg, NULL, 0, 0);
10492 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10493 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10494
10495 flush_events();
10496 flush_sequence();
10497 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
10498 ok(ret == 1, "expected 1, got %d\n", ret);
10499 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
10500 memset(&msg, 0xab, sizeof(msg));
10501 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
10502 ok(ret, "PeekMessage failed\n");
10503 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10504 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
10505 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
10506
10507 /* Check what happens to a WM_QUIT message posted to a window that gets
10508 * destroyed.
10509 */
10510 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
10511 0, 0, 100, 100, NULL, NULL, NULL, NULL);
10512 flush_sequence();
10513 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10514 {
10515 struct recvd_message rmsg;
10516 rmsg.hwnd = msg.hwnd;
10517 rmsg.message = msg.message;
10518 rmsg.flags = posted|wparam|lparam;
10519 rmsg.wParam = msg.wParam;
10520 rmsg.lParam = msg.lParam;
10521 rmsg.descr = "stop/quit";
10522 if (msg.message == WM_QUIT)
10523 /* The hwnd can only be checked here */
10524 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
10525 add_message(&rmsg);
10526 DispatchMessageA(&msg);
10527 }
10528 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
10529 }
10530
10531 static const struct message WmMouseHoverSeq[] = {
10532 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
10533 { WM_MOUSEACTIVATE, sent|optional },
10534 { WM_TIMER, sent|optional }, /* XP sends it */
10535 { WM_SYSTIMER, sent },
10536 { WM_MOUSEHOVER, sent|wparam, 0 },
10537 { 0 }
10538 };
10539
10540 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
10541 {
10542 MSG msg;
10543 DWORD start_ticks, end_ticks;
10544
10545 start_ticks = GetTickCount();
10546 /* add some deviation (50%) to cover not expected delays */
10547 start_ticks += timeout / 2;
10548
10549 do
10550 {
10551 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10552 {
10553 /* Timer proc messages are not dispatched to the window proc,
10554 * and therefore not logged.
10555 */
10556 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
10557 {
10558 struct recvd_message s_msg;
10559
10560 s_msg.hwnd = msg.hwnd;
10561 s_msg.message = msg.message;
10562 s_msg.flags = sent|wparam|lparam;
10563 s_msg.wParam = msg.wParam;
10564 s_msg.lParam = msg.lParam;
10565 s_msg.descr = "msg_loop";
10566 add_message(&s_msg);
10567 }
10568 DispatchMessageA(&msg);
10569 }
10570
10571 end_ticks = GetTickCount();
10572
10573 /* inject WM_MOUSEMOVE to see how it changes tracking */
10574 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
10575 {
10576 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10577 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10578
10579 inject_mouse_move = FALSE;
10580 }
10581 } while (start_ticks + timeout >= end_ticks);
10582 }
10583
10584 static void test_TrackMouseEvent(void)
10585 {
10586 TRACKMOUSEEVENT tme;
10587 BOOL ret;
10588 HWND hwnd, hchild;
10589 RECT rc_parent, rc_child;
10590 UINT default_hover_time, hover_width = 0, hover_height = 0;
10591
10592 #define track_hover(track_hwnd, track_hover_time) \
10593 tme.cbSize = sizeof(tme); \
10594 tme.dwFlags = TME_HOVER; \
10595 tme.hwndTrack = track_hwnd; \
10596 tme.dwHoverTime = track_hover_time; \
10597 SetLastError(0xdeadbeef); \
10598 ret = pTrackMouseEvent(&tme); \
10599 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
10600
10601 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
10602 tme.cbSize = sizeof(tme); \
10603 tme.dwFlags = TME_QUERY; \
10604 tme.hwndTrack = (HWND)0xdeadbeef; \
10605 tme.dwHoverTime = 0xdeadbeef; \
10606 SetLastError(0xdeadbeef); \
10607 ret = pTrackMouseEvent(&tme); \
10608 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
10609 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
10610 ok(tme.dwFlags == (expected_track_flags), \
10611 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
10612 ok(tme.hwndTrack == (expected_track_hwnd), \
10613 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
10614 ok(tme.dwHoverTime == (expected_hover_time), \
10615 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
10616
10617 #define track_hover_cancel(track_hwnd) \
10618 tme.cbSize = sizeof(tme); \
10619 tme.dwFlags = TME_HOVER | TME_CANCEL; \
10620 tme.hwndTrack = track_hwnd; \
10621 tme.dwHoverTime = 0xdeadbeef; \
10622 SetLastError(0xdeadbeef); \
10623 ret = pTrackMouseEvent(&tme); \
10624 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
10625
10626 default_hover_time = 0xdeadbeef;
10627 SetLastError(0xdeadbeef);
10628 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
10629 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10630 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
10631 if (!ret) default_hover_time = 400;
10632 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
10633
10634 SetLastError(0xdeadbeef);
10635 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
10636 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10637 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
10638 if (!ret) hover_width = 4;
10639 SetLastError(0xdeadbeef);
10640 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
10641 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10642 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
10643 if (!ret) hover_height = 4;
10644 trace("hover rect is %u x %d\n", hover_width, hover_height);
10645
10646 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10647 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10648 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10649 NULL, NULL, 0);
10650 assert(hwnd);
10651
10652 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
10653 WS_CHILD | WS_BORDER | WS_VISIBLE,
10654 50, 50, 200, 200, hwnd,
10655 NULL, NULL, 0);
10656 assert(hchild);
10657
10658 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
10659 flush_events();
10660 flush_sequence();
10661
10662 tme.cbSize = 0;
10663 tme.dwFlags = TME_QUERY;
10664 tme.hwndTrack = (HWND)0xdeadbeef;
10665 tme.dwHoverTime = 0xdeadbeef;
10666 SetLastError(0xdeadbeef);
10667 ret = pTrackMouseEvent(&tme);
10668 ok(!ret, "TrackMouseEvent should fail\n");
10669 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
10670 "not expected error %u\n", GetLastError());
10671
10672 tme.cbSize = sizeof(tme);
10673 tme.dwFlags = TME_HOVER;
10674 tme.hwndTrack = (HWND)0xdeadbeef;
10675 tme.dwHoverTime = 0xdeadbeef;
10676 SetLastError(0xdeadbeef);
10677 ret = pTrackMouseEvent(&tme);
10678 ok(!ret, "TrackMouseEvent should fail\n");
10679 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10680 "not expected error %u\n", GetLastError());
10681
10682 tme.cbSize = sizeof(tme);
10683 tme.dwFlags = TME_HOVER | TME_CANCEL;
10684 tme.hwndTrack = (HWND)0xdeadbeef;
10685 tme.dwHoverTime = 0xdeadbeef;
10686 SetLastError(0xdeadbeef);
10687 ret = pTrackMouseEvent(&tme);
10688 ok(!ret, "TrackMouseEvent should fail\n");
10689 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10690 "not expected error %u\n", GetLastError());
10691
10692 GetWindowRect(hwnd, &rc_parent);
10693 GetWindowRect(hchild, &rc_child);
10694 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
10695
10696 /* Process messages so that the system updates its internal current
10697 * window and hittest, otherwise TrackMouseEvent calls don't have any
10698 * effect.
10699 */
10700 flush_events();
10701 flush_sequence();
10702
10703 track_query(0, NULL, 0);
10704 track_hover(hchild, 0);
10705 track_query(0, NULL, 0);
10706
10707 flush_events();
10708 flush_sequence();
10709
10710 track_hover(hwnd, 0);
10711 tme.cbSize = sizeof(tme);
10712 tme.dwFlags = TME_QUERY;
10713 tme.hwndTrack = (HWND)0xdeadbeef;
10714 tme.dwHoverTime = 0xdeadbeef;
10715 SetLastError(0xdeadbeef);
10716 ret = pTrackMouseEvent(&tme);
10717 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10718 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10719 if (!tme.dwFlags)
10720 {
10721 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10722 DestroyWindow( hwnd );
10723 return;
10724 }
10725 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10726 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10727 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10728 tme.dwHoverTime, default_hover_time);
10729
10730 pump_msg_loop_timeout(default_hover_time, FALSE);
10731 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10732
10733 track_query(0, NULL, 0);
10734
10735 track_hover(hwnd, HOVER_DEFAULT);
10736 track_query(TME_HOVER, hwnd, default_hover_time);
10737
10738 Sleep(default_hover_time / 2);
10739 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10740 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10741
10742 track_query(TME_HOVER, hwnd, default_hover_time);
10743
10744 pump_msg_loop_timeout(default_hover_time, FALSE);
10745 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10746
10747 track_query(0, NULL, 0);
10748
10749 track_hover(hwnd, HOVER_DEFAULT);
10750 track_query(TME_HOVER, hwnd, default_hover_time);
10751
10752 pump_msg_loop_timeout(default_hover_time, TRUE);
10753 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10754
10755 track_query(0, NULL, 0);
10756
10757 track_hover(hwnd, HOVER_DEFAULT);
10758 track_query(TME_HOVER, hwnd, default_hover_time);
10759 track_hover_cancel(hwnd);
10760
10761 DestroyWindow(hwnd);
10762
10763 #undef track_hover
10764 #undef track_query
10765 #undef track_hover_cancel
10766 }
10767
10768
10769 static const struct message WmSetWindowRgn[] = {
10770 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10771 { WM_NCCALCSIZE, sent|wparam, 1 },
10772 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10773 { WM_GETTEXT, sent|defwinproc|optional },
10774 { WM_ERASEBKGND, sent|optional },
10775 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10776 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10777 { 0 }
10778 };
10779
10780 static const struct message WmSetWindowRgn_no_redraw[] = {
10781 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10782 { WM_NCCALCSIZE, sent|wparam, 1 },
10783 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10784 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10785 { 0 }
10786 };
10787
10788 static const struct message WmSetWindowRgn_clear[] = {
10789 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10790 { WM_NCCALCSIZE, sent|wparam, 1 },
10791 { WM_NCPAINT, sent|optional },
10792 { WM_GETTEXT, sent|defwinproc|optional },
10793 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10794 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10795 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10796 { WM_NCPAINT, sent|optional },
10797 { WM_GETTEXT, sent|defwinproc|optional },
10798 { WM_ERASEBKGND, sent|optional },
10799 { WM_WINDOWPOSCHANGING, sent|optional },
10800 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10801 { WM_NCPAINT, sent|optional },
10802 { WM_GETTEXT, sent|defwinproc|optional },
10803 { WM_ERASEBKGND, sent|optional },
10804 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10805 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10806 { WM_NCPAINT, sent|optional },
10807 { WM_GETTEXT, sent|defwinproc|optional },
10808 { WM_ERASEBKGND, sent|optional },
10809 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10810 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10811 { 0 }
10812 };
10813
10814 static void test_SetWindowRgn(void)
10815 {
10816 HRGN hrgn;
10817 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10818 100, 100, 200, 200, 0, 0, 0, NULL);
10819 ok( hwnd != 0, "Failed to create overlapped window\n" );
10820
10821 ShowWindow( hwnd, SW_SHOW );
10822 UpdateWindow( hwnd );
10823 flush_events();
10824 flush_sequence();
10825
10826 trace("testing SetWindowRgn\n");
10827 hrgn = CreateRectRgn( 0, 0, 150, 150 );
10828 SetWindowRgn( hwnd, hrgn, TRUE );
10829 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10830
10831 hrgn = CreateRectRgn( 30, 30, 160, 160 );
10832 SetWindowRgn( hwnd, hrgn, FALSE );
10833 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10834
10835 hrgn = CreateRectRgn( 0, 0, 180, 180 );
10836 SetWindowRgn( hwnd, hrgn, TRUE );
10837 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10838
10839 SetWindowRgn( hwnd, 0, TRUE );
10840 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10841
10842 DestroyWindow( hwnd );
10843 }
10844
10845 /*************************** ShowWindow() test ******************************/
10846 static const struct message WmShowNormal[] = {
10847 { WM_SHOWWINDOW, sent|wparam, 1 },
10848 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10849 { HCBT_ACTIVATE, hook },
10850 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10851 { HCBT_SETFOCUS, hook },
10852 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10853 { 0 }
10854 };
10855 static const struct message WmShow[] = {
10856 { WM_SHOWWINDOW, sent|wparam, 1 },
10857 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10858 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10859 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10860 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10861 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10862 { 0 }
10863 };
10864 static const struct message WmShowNoActivate_1[] = {
10865 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10866 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10867 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10868 { WM_MOVE, sent|defwinproc|optional },
10869 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10870 { 0 }
10871 };
10872 static const struct message WmShowNoActivate_2[] = {
10873 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10874 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
10875 { HCBT_ACTIVATE, hook|optional },
10876 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10877 { HCBT_SETFOCUS, hook|optional },
10878 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
10879 { WM_MOVE, sent|defwinproc },
10880 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10881 { HCBT_SETFOCUS, hook|optional },
10882 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10883 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10884 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10885 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10886 { 0 }
10887 };
10888 static const struct message WmShowNA_1[] = {
10889 { WM_SHOWWINDOW, sent|wparam, 1 },
10890 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10891 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10892 { 0 }
10893 };
10894 static const struct message WmShowNA_2[] = {
10895 { WM_SHOWWINDOW, sent|wparam, 1 },
10896 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10897 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10898 { 0 }
10899 };
10900 static const struct message WmRestore_1[] = {
10901 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10902 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10903 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10904 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10905 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10906 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10907 { WM_MOVE, sent|defwinproc },
10908 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10909 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10910 { 0 }
10911 };
10912 static const struct message WmRestore_2[] = {
10913 { WM_SHOWWINDOW, sent|wparam, 1 },
10914 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10915 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10916 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10917 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10918 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10919 { 0 }
10920 };
10921 static const struct message WmRestore_3[] = {
10922 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10923 { WM_GETMINMAXINFO, sent },
10924 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10925 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10926 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10927 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10928 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10929 { WM_MOVE, sent|defwinproc },
10930 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10931 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10932 { 0 }
10933 };
10934 static const struct message WmRestore_4[] = {
10935 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10936 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10937 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10938 { WM_MOVE, sent|defwinproc|optional },
10939 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10940 { 0 }
10941 };
10942 static const struct message WmRestore_5[] = {
10943 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10944 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10945 { HCBT_ACTIVATE, hook|optional },
10946 { HCBT_SETFOCUS, hook|optional },
10947 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10948 { WM_MOVE, sent|defwinproc|optional },
10949 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10950 { 0 }
10951 };
10952 static const struct message WmHide_1[] = {
10953 { WM_SHOWWINDOW, sent|wparam, 0 },
10954 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
10955 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
10956 { HCBT_ACTIVATE, hook|optional },
10957 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10958 { 0 }
10959 };
10960 static const struct message WmHide_2[] = {
10961 { WM_SHOWWINDOW, sent|wparam, 0 },
10962 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10963 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10964 { HCBT_ACTIVATE, hook|optional },
10965 { 0 }
10966 };
10967 static const struct message WmHide_3[] = {
10968 { WM_SHOWWINDOW, sent|wparam, 0 },
10969 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10970 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10971 { HCBT_SETFOCUS, hook|optional },
10972 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10973 { 0 }
10974 };
10975 static const struct message WmShowMinimized_1[] = {
10976 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10977 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10978 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10979 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10980 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10981 { WM_MOVE, sent|defwinproc },
10982 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10983 { 0 }
10984 };
10985 static const struct message WmMinimize_1[] = {
10986 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10987 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10988 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10989 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10990 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10991 { WM_MOVE, sent|defwinproc },
10992 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10993 { 0 }
10994 };
10995 static const struct message WmMinimize_2[] = {
10996 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10997 { HCBT_SETFOCUS, hook|optional },
10998 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
10999 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
11000 { WM_MOVE, sent|defwinproc },
11001 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
11002 { 0 }
11003 };
11004 static const struct message WmMinimize_3[] = {
11005 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
11006 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
11007 { HCBT_ACTIVATE, hook|optional },
11008 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11009 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
11010 { WM_MOVE, sent|defwinproc },
11011 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
11012 { 0 }
11013 };
11014 static const struct message WmShowMinNoActivate[] = {
11015 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
11016 { WM_WINDOWPOSCHANGING, sent },
11017 { WM_WINDOWPOSCHANGED, sent },
11018 { WM_MOVE, sent|defwinproc|optional },
11019 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
11020 { 0 }
11021 };
11022 static const struct message WmMinMax_1[] = {
11023 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
11024 { 0 }
11025 };
11026 static const struct message WmMinMax_2[] = {
11027 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11028 { WM_GETMINMAXINFO, sent|optional },
11029 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
11030 { HCBT_ACTIVATE, hook|optional },
11031 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11032 { HCBT_SETFOCUS, hook|optional },
11033 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11034 { WM_MOVE, sent|defwinproc|optional },
11035 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
11036 { HCBT_SETFOCUS, hook|optional },
11037 { 0 }
11038 };
11039 static const struct message WmMinMax_3[] = {
11040 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
11041 { HCBT_SETFOCUS, hook|optional },
11042 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11043 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11044 { WM_MOVE, sent|defwinproc|optional },
11045 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
11046 { 0 }
11047 };
11048 static const struct message WmMinMax_4[] = {
11049 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
11050 { 0 }
11051 };
11052 static const struct message WmShowMaximized_1[] = {
11053 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11054 { WM_GETMINMAXINFO, sent },
11055 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11056 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
11057 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
11058 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
11059 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11060 { WM_MOVE, sent|defwinproc },
11061 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11062 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
11063 { 0 }
11064 };
11065 static const struct message WmShowMaximized_2[] = {
11066 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11067 { WM_GETMINMAXINFO, sent },
11068 { WM_WINDOWPOSCHANGING, sent|optional },
11069 { HCBT_ACTIVATE, hook|optional },
11070 { WM_WINDOWPOSCHANGED, sent|optional },
11071 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
11072 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
11073 { WM_WINDOWPOSCHANGING, sent|optional },
11074 { HCBT_SETFOCUS, hook|optional },
11075 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11076 { WM_MOVE, sent|defwinproc },
11077 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11078 { HCBT_SETFOCUS, hook|optional },
11079 { 0 }
11080 };
11081 static const struct message WmShowMaximized_3[] = {
11082 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11083 { WM_GETMINMAXINFO, sent|optional },
11084 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
11085 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
11086 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
11087 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
11088 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
11089 { WM_MOVE, sent|defwinproc|optional },
11090 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11091 { 0 }
11092 };
11093
11094 static void test_ShowWindow(void)
11095 {
11096 /* ShowWindow commands in random order */
11097 static const struct
11098 {
11099 INT cmd; /* ShowWindow command */
11100 LPARAM ret; /* ShowWindow return value */
11101 DWORD style; /* window style after the command */
11102 const struct message *msg; /* message sequence the command produces */
11103 INT wp_cmd, wp_flags; /* window placement after the command */
11104 POINT wp_min, wp_max; /* window placement after the command */
11105 BOOL todo_msg; /* message sequence doesn't match what Wine does */
11106 } sw[] =
11107 {
11108 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
11109 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11110 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
11111 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11112 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
11113 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11114 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11115 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11116 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
11117 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11118 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
11119 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11120 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
11121 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11122 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11123 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11124 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
11125 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11126 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
11127 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11128 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
11129 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11130 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
11131 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11132 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
11133 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11134 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
11135 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11136 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
11137 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11138 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11139 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11140 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
11141 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11142 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
11143 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11144 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
11145 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11146 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11147 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11148 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11149 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11150 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
11151 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
11152 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
11153 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11154 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11155 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11156 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11157 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11158 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
11159 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11160 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
11161 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11162 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11163 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11164 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11165 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11166 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
11167 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11168 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
11169 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11170 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
11171 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11172 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11173 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11174 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
11175 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11176 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
11177 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11178 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11179 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11180 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
11181 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11182 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
11183 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11184 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
11185 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11186 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
11187 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11188 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11189 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11190 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
11191 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11192 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
11193 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11194 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
11195 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11196 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11197 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11198 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
11199 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11200 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
11201 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11202 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
11203 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11204 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
11205 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11206 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
11207 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11208 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
11209 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11210 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
11211 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11212 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11213 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11214 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
11215 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11216 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11217 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11218 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
11219 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11220 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
11221 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
11222 };
11223 HWND hwnd;
11224 DWORD style;
11225 LPARAM ret;
11226 INT i;
11227 WINDOWPLACEMENT wp;
11228 RECT win_rc, work_rc = {0, 0, 0, 0};
11229
11230 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
11231 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
11232 120, 120, 90, 90,
11233 0, 0, 0, NULL);
11234 assert(hwnd);
11235
11236 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
11237 ok(style == 0, "expected style 0, got %08x\n", style);
11238
11239 flush_events();
11240 flush_sequence();
11241
11242 if (pGetMonitorInfoA && pMonitorFromPoint)
11243 {
11244 HMONITOR hmon;
11245 MONITORINFO mi;
11246 POINT pt = {0, 0};
11247
11248 SetLastError(0xdeadbeef);
11249 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
11250 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
11251
11252 mi.cbSize = sizeof(mi);
11253 SetLastError(0xdeadbeef);
11254 ret = pGetMonitorInfoA(hmon, &mi);
11255 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
11256 trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n",
11257 mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom,
11258 mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
11259 work_rc = mi.rcWork;
11260 }
11261
11262 GetWindowRect(hwnd, &win_rc);
11263 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
11264
11265 wp.length = sizeof(wp);
11266 SetLastError(0xdeadbeaf);
11267 ret = GetWindowPlacement(hwnd, &wp);
11268 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11269 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
11270 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
11271 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
11272 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
11273 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
11274 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11275 if (work_rc.left || work_rc.top) todo_wine /* FIXME: remove once Wine is fixed */
11276 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11277 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11278 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11279 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11280 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11281 else
11282 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11283 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11284 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11285 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11286 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11287
11288 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
11289 {
11290 static const char * const sw_cmd_name[13] =
11291 {
11292 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
11293 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
11294 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
11295 "SW_NORMALNA" /* 0xCC */
11296 };
11297 char comment[64];
11298 INT idx; /* index into the above array of names */
11299
11300 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
11301
11302 style = GetWindowLongA(hwnd, GWL_STYLE);
11303 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
11304 ret = ShowWindow(hwnd, sw[i].cmd);
11305 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
11306 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
11307 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
11308
11309 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
11310 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
11311
11312 wp.length = sizeof(wp);
11313 SetLastError(0xdeadbeaf);
11314 ret = GetWindowPlacement(hwnd, &wp);
11315 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11316 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
11317 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
11318
11319 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
11320 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
11321 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
11322 {
11323 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
11324 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
11325 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11326 }
11327 else
11328 {
11329 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
11330 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11331 }
11332
11333 if (wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
11334 todo_wine
11335 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11336 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11337 else
11338 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11339 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11340
11341 if (0) /* FIXME: Wine behaves completely different here */
11342 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11343 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11344 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11345 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11346 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11347 }
11348 DestroyWindow(hwnd);
11349 flush_events();
11350 }
11351
11352 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11353 {
11354 struct recvd_message msg;
11355
11356 if (ignore_message( message )) return 0;
11357
11358 msg.hwnd = hwnd;
11359 msg.message = message;
11360 msg.flags = sent|wparam|lparam;
11361 msg.wParam = wParam;
11362 msg.lParam = lParam;
11363 msg.descr = "dialog";
11364 add_message(&msg);
11365
11366 /* calling DefDlgProc leads to a recursion under XP */
11367
11368 switch (message)
11369 {
11370 case WM_INITDIALOG:
11371 case WM_GETDLGCODE:
11372 return 0;
11373 }
11374 return 1;
11375 }
11376
11377 static const struct message WmDefDlgSetFocus_1[] = {
11378 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11379 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11380 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11381 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11382 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11383 { HCBT_SETFOCUS, hook },
11384 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11385 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11386 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11387 { WM_SETFOCUS, sent|wparam, 0 },
11388 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11389 { WM_CTLCOLOREDIT, sent },
11390 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11391 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11392 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11393 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11394 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
11395 { 0 }
11396 };
11397 static const struct message WmDefDlgSetFocus_2[] = {
11398 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11399 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11400 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11401 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11402 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11403 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11404 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
11405 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11406 { 0 }
11407 };
11408 /* Creation of a dialog */
11409 static const struct message WmCreateDialogParamSeq_1[] = {
11410 { HCBT_CREATEWND, hook },
11411 { WM_NCCREATE, sent },
11412 { WM_NCCALCSIZE, sent|wparam, 0 },
11413 { WM_CREATE, sent },
11414 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11415 { WM_SIZE, sent|wparam, SIZE_RESTORED },
11416 { WM_MOVE, sent },
11417 { WM_SETFONT, sent },
11418 { WM_INITDIALOG, sent },
11419 { WM_CHANGEUISTATE, sent|optional },
11420 { 0 }
11421 };
11422 /* Creation of a dialog */
11423 static const struct message WmCreateDialogParamSeq_2[] = {
11424 { HCBT_CREATEWND, hook },
11425 { WM_NCCREATE, sent },
11426 { WM_NCCALCSIZE, sent|wparam, 0 },
11427 { WM_CREATE, sent },
11428 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11429 { WM_SIZE, sent|wparam, SIZE_RESTORED },
11430 { WM_MOVE, sent },
11431 { WM_CHANGEUISTATE, sent|optional },
11432 { 0 }
11433 };
11434
11435 static void test_dialog_messages(void)
11436 {
11437 WNDCLASSA cls;
11438 HWND hdlg, hedit1, hedit2, hfocus;
11439 LRESULT ret;
11440
11441 #define set_selection(hctl, start, end) \
11442 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
11443 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
11444
11445 #define check_selection(hctl, start, end) \
11446 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
11447 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
11448
11449 subclass_edit();
11450
11451 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
11452 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
11453 0, 0, 100, 100, 0, 0, 0, NULL);
11454 ok(hdlg != 0, "Failed to create custom dialog window\n");
11455
11456 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
11457 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11458 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
11459 ok(hedit1 != 0, "Failed to create edit control\n");
11460 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
11461 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11462 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
11463 ok(hedit2 != 0, "Failed to create edit control\n");
11464
11465 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
11466 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
11467
11468 hfocus = GetFocus();
11469 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
11470
11471 SetFocus(hedit2);
11472 hfocus = GetFocus();
11473 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
11474
11475 check_selection(hedit1, 0, 0);
11476 check_selection(hedit2, 0, 0);
11477
11478 set_selection(hedit2, 0, -1);
11479 check_selection(hedit2, 0, 3);
11480
11481 SetFocus(0);
11482 hfocus = GetFocus();
11483 ok(hfocus == 0, "wrong focus %p\n", hfocus);
11484
11485 flush_sequence();
11486 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
11487 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11488 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
11489
11490 hfocus = GetFocus();
11491 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11492
11493 check_selection(hedit1, 0, 5);
11494 check_selection(hedit2, 0, 3);
11495
11496 flush_sequence();
11497 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
11498 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11499 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
11500
11501 hfocus = GetFocus();
11502 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11503
11504 check_selection(hedit1, 0, 5);
11505 check_selection(hedit2, 0, 3);
11506
11507 EndDialog(hdlg, 0);
11508 DestroyWindow(hedit1);
11509 DestroyWindow(hedit2);
11510 DestroyWindow(hdlg);
11511 flush_sequence();
11512
11513 #undef set_selection
11514 #undef check_selection
11515
11516 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11517 cls.lpszClassName = "MyDialogClass";
11518 cls.hInstance = GetModuleHandleA(NULL);
11519 /* need a cast since a dlgproc is used as a wndproc */
11520 cls.lpfnWndProc = test_dlg_proc;
11521 if (!RegisterClassA(&cls)) assert(0);
11522
11523 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
11524 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11525 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
11526 EndDialog(hdlg, 0);
11527 DestroyWindow(hdlg);
11528 flush_sequence();
11529
11530 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
11531 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11532 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
11533 EndDialog(hdlg, 0);
11534 DestroyWindow(hdlg);
11535 flush_sequence();
11536
11537 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11538 }
11539
11540 static void test_EndDialog(void)
11541 {
11542 HWND hparent, hother, hactive, hdlg;
11543 WNDCLASSA cls;
11544
11545 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
11546 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
11547 100, 100, 200, 200, 0, 0, 0, NULL);
11548 ok (hparent != 0, "Failed to create parent window\n");
11549
11550 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
11551 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11552 100, 100, 200, 200, 0, 0, 0, NULL);
11553 ok (hother != 0, "Failed to create parent window\n");
11554
11555 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11556 cls.lpszClassName = "MyDialogClass";
11557 cls.hInstance = GetModuleHandleA(NULL);
11558 cls.lpfnWndProc = test_dlg_proc;
11559 if (!RegisterClassA(&cls)) assert(0);
11560
11561 flush_sequence();
11562 SetForegroundWindow(hother);
11563 hactive = GetForegroundWindow();
11564 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
11565
11566 /* create a dialog where the parent is disabled, this parent should still
11567 receive the focus when the dialog exits (even though "normally" a
11568 disabled window should not receive the focus) */
11569 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
11570 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11571 SetForegroundWindow(hdlg);
11572 hactive = GetForegroundWindow();
11573 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
11574 EndDialog(hdlg, 0);
11575 hactive = GetForegroundWindow();
11576 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
11577 DestroyWindow(hdlg);
11578 flush_sequence();
11579
11580 DestroyWindow( hother );
11581 DestroyWindow( hparent );
11582 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11583 }
11584
11585 static void test_nullCallback(void)
11586 {
11587 HWND hwnd;
11588
11589 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
11590 100, 100, 200, 200, 0, 0, 0, NULL);
11591 ok (hwnd != 0, "Failed to create overlapped window\n");
11592
11593 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
11594 flush_events();
11595 DestroyWindow(hwnd);
11596 }
11597
11598 /* SetActiveWindow( 0 ) hwnd visible */
11599 static const struct message SetActiveWindowSeq0[] =
11600 {
11601 { HCBT_ACTIVATE, hook|optional },
11602 { WM_NCACTIVATE, sent|wparam, 0 },
11603 { WM_GETTEXT, sent|defwinproc|optional },
11604 { WM_ACTIVATE, sent|wparam, 0 },
11605 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11606 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11607 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11608 { WM_KILLFOCUS, sent|optional },
11609 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11610 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11611 { WM_NCACTIVATE, sent|wparam|optional, 1 },
11612 { WM_GETTEXT, sent|defwinproc|optional },
11613 { WM_ACTIVATE, sent|wparam|optional, 1 },
11614 { HCBT_SETFOCUS, hook|optional },
11615 { WM_KILLFOCUS, sent|defwinproc|optional },
11616 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11617 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11618 { WM_IME_SETCONTEXT, sent|optional },
11619 { WM_IME_SETCONTEXT, sent|optional },
11620 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11621 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11622 { WM_SETFOCUS, sent|defwinproc|optional },
11623 { WM_GETTEXT, sent|optional },
11624 { 0 }
11625 };
11626 /* SetActiveWindow( hwnd ) hwnd visible */
11627 static const struct message SetActiveWindowSeq1[] =
11628 {
11629 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11630 { 0 }
11631 };
11632 /* SetActiveWindow( popup ) hwnd visible, popup visible */
11633 static const struct message SetActiveWindowSeq2[] =
11634 {
11635 { HCBT_ACTIVATE, hook },
11636 { WM_NCACTIVATE, sent|wparam, 0 },
11637 { WM_GETTEXT, sent|defwinproc|optional },
11638 { WM_ACTIVATE, sent|wparam, 0 },
11639 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11640 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11641 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11642 { WM_NCPAINT, sent|optional },
11643 { WM_GETTEXT, sent|defwinproc|optional },
11644 { WM_ERASEBKGND, sent|optional },
11645 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11646 { WM_NCACTIVATE, sent|wparam, 1 },
11647 { WM_GETTEXT, sent|defwinproc|optional },
11648 { WM_ACTIVATE, sent|wparam, 1 },
11649 { HCBT_SETFOCUS, hook },
11650 { WM_KILLFOCUS, sent|defwinproc },
11651 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11652 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11653 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11654 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11655 { WM_SETFOCUS, sent|defwinproc },
11656 { WM_GETTEXT, sent|optional },
11657 { 0 }
11658 };
11659
11660 /* SetActiveWindow( hwnd ) hwnd not visible */
11661 static const struct message SetActiveWindowSeq3[] =
11662 {
11663 { HCBT_ACTIVATE, hook },
11664 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11665 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11666 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11667 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11668 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11669 { WM_ACTIVATEAPP, sent|wparam, 1 },
11670 { WM_ACTIVATEAPP, sent|wparam, 1 },
11671 { WM_NCACTIVATE, sent|wparam, 1 },
11672 { WM_ACTIVATE, sent|wparam, 1 },
11673 { HCBT_SETFOCUS, hook },
11674 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11675 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11676 { WM_SETFOCUS, sent|defwinproc },
11677 { 0 }
11678 };
11679 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
11680 static const struct message SetActiveWindowSeq4[] =
11681 {
11682 { HCBT_ACTIVATE, hook },
11683 { WM_NCACTIVATE, sent|wparam, 0 },
11684 { WM_GETTEXT, sent|defwinproc|optional },
11685 { WM_ACTIVATE, sent|wparam, 0 },
11686 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11687 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11688 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11689 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11690 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11691 { WM_NCACTIVATE, sent|wparam, 1 },
11692 { WM_GETTEXT, sent|defwinproc|optional },
11693 { WM_ACTIVATE, sent|wparam, 1 },
11694 { HCBT_SETFOCUS, hook },
11695 { WM_KILLFOCUS, sent|defwinproc },
11696 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11697 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11698 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11699 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11700 { WM_SETFOCUS, sent|defwinproc },
11701 { 0 }
11702 };
11703
11704
11705 static void test_SetActiveWindow(void)
11706 {
11707 HWND hwnd, popup, ret;
11708
11709 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11710 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11711 100, 100, 200, 200, 0, 0, 0, NULL);
11712
11713 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11714 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
11715 100, 100, 200, 200, hwnd, 0, 0, NULL);
11716
11717 ok(hwnd != 0, "Failed to create overlapped window\n");
11718 ok(popup != 0, "Failed to create popup window\n");
11719 SetForegroundWindow( popup );
11720 flush_sequence();
11721
11722 trace("SetActiveWindow(0)\n");
11723 ret = SetActiveWindow(0);
11724 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
11725 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
11726 flush_sequence();
11727
11728 trace("SetActiveWindow(hwnd), hwnd visible\n");
11729 ret = SetActiveWindow(hwnd);
11730 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
11731 flush_sequence();
11732
11733 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
11734 ret = SetActiveWindow(popup);
11735 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
11736 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
11737 flush_sequence();
11738
11739 ShowWindow(hwnd, SW_HIDE);
11740 ShowWindow(popup, SW_HIDE);
11741 flush_sequence();
11742
11743 trace("SetActiveWindow(hwnd), hwnd not visible\n");
11744 ret = SetActiveWindow(hwnd);
11745 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
11746 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
11747 flush_sequence();
11748
11749 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
11750 ret = SetActiveWindow(popup);
11751 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
11752 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
11753 flush_sequence();
11754
11755 trace("done\n");
11756
11757 DestroyWindow(hwnd);
11758 }
11759
11760 static const struct message SetForegroundWindowSeq[] =
11761 {
11762 { WM_NCACTIVATE, sent|wparam, 0 },
11763 { WM_GETTEXT, sent|defwinproc|optional },
11764 { WM_ACTIVATE, sent|wparam, 0 },
11765 { WM_ACTIVATEAPP, sent|wparam, 0 },
11766 { WM_KILLFOCUS, sent },
11767 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11768 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
11769 { 0 }
11770 };
11771
11772 static void test_SetForegroundWindow(void)
11773 {
11774 HWND hwnd;
11775
11776 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
11777 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11778 100, 100, 200, 200, 0, 0, 0, NULL);
11779 ok (hwnd != 0, "Failed to create overlapped window\n");
11780 SetForegroundWindow( hwnd );
11781 flush_sequence();
11782
11783 trace("SetForegroundWindow( 0 )\n");
11784 SetForegroundWindow( 0 );
11785 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
11786 trace("SetForegroundWindow( GetDesktopWindow() )\n");
11787 SetForegroundWindow( GetDesktopWindow() );
11788 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
11789 "foreground top level window", FALSE);
11790 trace("done\n");
11791
11792 DestroyWindow(hwnd);
11793 }
11794
11795 static void test_dbcs_wm_char(void)
11796 {
11797 BYTE dbch[2];
11798 WCHAR wch, bad_wch;
11799 HWND hwnd, hwnd2;
11800 MSG msg;
11801 DWORD time;
11802 POINT pt;
11803 DWORD_PTR res;
11804 CPINFOEXA cpinfo;
11805 UINT i, j, k;
11806 struct message wmCharSeq[2];
11807 BOOL ret;
11808
11809 if (!pGetCPInfoExA)
11810 {
11811 win_skip("GetCPInfoExA is not available\n");
11812 return;
11813 }
11814
11815 pGetCPInfoExA( CP_ACP, 0, &cpinfo );
11816 if (cpinfo.MaxCharSize != 2)
11817 {
11818 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
11819 return;
11820 }
11821
11822 dbch[0] = dbch[1] = 0;
11823 wch = 0;
11824 bad_wch = cpinfo.UnicodeDefaultChar;
11825 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
11826 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
11827 for (k = 128; k <= 255; k++)
11828 {
11829 char str[2];
11830 WCHAR wstr[2];
11831 str[0] = j;
11832 str[1] = k;
11833 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
11834 WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
11835 (BYTE)str[0] == j && (BYTE)str[1] == k &&
11836 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
11837 {
11838 dbch[0] = j;
11839 dbch[1] = k;
11840 wch = wstr[0];
11841 break;
11842 }
11843 }
11844
11845 if (!wch)
11846 {
11847 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
11848 return;
11849 }
11850 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
11851 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
11852
11853 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
11854 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11855 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
11856 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11857 ok (hwnd != 0, "Failed to create overlapped window\n");
11858 ok (hwnd2 != 0, "Failed to create overlapped window\n");
11859 flush_sequence();
11860
11861 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
11862 wmCharSeq[0].message = WM_CHAR;
11863 wmCharSeq[0].flags = sent|wparam;
11864 wmCharSeq[0].wParam = wch;
11865
11866 /* posted message */
11867 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11868 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11869 ok( !ret, "got message %x\n", msg.message );
11870 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11871 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11872 ok( ret, "no message\n" );
11873 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11874 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11875 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11876 ok( !ret, "got message %x\n", msg.message );
11877
11878 /* posted thread message */
11879 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
11880 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11881 ok( !ret, "got message %x\n", msg.message );
11882 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11883 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11884 ok( ret, "no message\n" );
11885 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11886 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11887 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11888 ok( !ret, "got message %x\n", msg.message );
11889
11890 /* sent message */
11891 flush_sequence();
11892 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11893 ok_sequence( WmEmptySeq, "no messages", FALSE );
11894 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11895 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11896 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11897 ok( !ret, "got message %x\n", msg.message );
11898
11899 /* sent message with timeout */
11900 flush_sequence();
11901 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11902 ok_sequence( WmEmptySeq, "no messages", FALSE );
11903 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11904 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11905 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11906 ok( !ret, "got message %x\n", msg.message );
11907
11908 /* sent message with timeout and callback */
11909 flush_sequence();
11910 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11911 ok_sequence( WmEmptySeq, "no messages", FALSE );
11912 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11913 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11914 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11915 ok( !ret, "got message %x\n", msg.message );
11916
11917 /* sent message with callback */
11918 flush_sequence();
11919 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11920 ok_sequence( WmEmptySeq, "no messages", FALSE );
11921 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11922 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11923 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11924 ok( !ret, "got message %x\n", msg.message );
11925
11926 /* direct window proc call */
11927 flush_sequence();
11928 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11929 ok_sequence( WmEmptySeq, "no messages", FALSE );
11930 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11931 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11932
11933 /* dispatch message */
11934 msg.hwnd = hwnd;
11935 msg.message = WM_CHAR;
11936 msg.wParam = dbch[0];
11937 msg.lParam = 0;
11938 DispatchMessageA( &msg );
11939 ok_sequence( WmEmptySeq, "no messages", FALSE );
11940 msg.wParam = dbch[1];
11941 DispatchMessageA( &msg );
11942 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11943
11944 /* window handle is irrelevant */
11945 flush_sequence();
11946 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11947 ok_sequence( WmEmptySeq, "no messages", FALSE );
11948 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11949 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11950 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11951 ok( !ret, "got message %x\n", msg.message );
11952
11953 /* interleaved post and send */
11954 flush_sequence();
11955 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11956 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11957 ok_sequence( WmEmptySeq, "no messages", FALSE );
11958 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11959 ok( !ret, "got message %x\n", msg.message );
11960 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11961 ok_sequence( WmEmptySeq, "no messages", FALSE );
11962 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11963 ok( ret, "no message\n" );
11964 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11965 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11966 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11967 ok( !ret, "got message %x\n", msg.message );
11968 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11969 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11970 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11971 ok( !ret, "got message %x\n", msg.message );
11972
11973 /* interleaved sent message and winproc */
11974 flush_sequence();
11975 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11976 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11977 ok_sequence( WmEmptySeq, "no messages", FALSE );
11978 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11979 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11980 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11981 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11982
11983 /* interleaved winproc and dispatch */
11984 msg.hwnd = hwnd;
11985 msg.message = WM_CHAR;
11986 msg.wParam = dbch[0];
11987 msg.lParam = 0;
11988 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11989 DispatchMessageA( &msg );
11990 ok_sequence( WmEmptySeq, "no messages", FALSE );
11991 msg.wParam = dbch[1];
11992 DispatchMessageA( &msg );
11993 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11994 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11995 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11996
11997 /* interleaved sends */
11998 flush_sequence();
11999 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
12000 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
12001 ok_sequence( WmEmptySeq, "no messages", FALSE );
12002 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
12003 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12004 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
12005 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12006
12007 /* dbcs WM_CHAR */
12008 flush_sequence();
12009 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
12010 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12011 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12012 ok( !ret, "got message %x\n", msg.message );
12013
12014 /* other char messages are not magic */
12015 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
12016 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12017 ok( ret, "no message\n" );
12018 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
12019 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
12020 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12021 ok( !ret, "got message %x\n", msg.message );
12022 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
12023 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12024 ok( ret, "no message\n" );
12025 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
12026 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
12027 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12028 ok( !ret, "got message %x\n", msg.message );
12029
12030 /* test retrieving messages */
12031
12032 PostMessageW( hwnd, WM_CHAR, wch, 0 );
12033 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12034 ok( ret, "no message\n" );
12035 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12036 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12037 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12038 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12039 ok( ret, "no message\n" );
12040 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12041 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12042 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12043 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12044 ok( !ret, "got message %x\n", msg.message );
12045
12046 /* message filters */
12047 PostMessageW( hwnd, WM_CHAR, wch, 0 );
12048 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12049 ok( ret, "no message\n" );
12050 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12051 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12052 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12053 /* message id is filtered, hwnd is not */
12054 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
12055 ok( !ret, "no message\n" );
12056 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
12057 ok( ret, "no message\n" );
12058 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12059 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12060 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12061 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12062 ok( !ret, "got message %x\n", msg.message );
12063
12064 /* mixing GetMessage and PostMessage */
12065 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
12066 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12067 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12068 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12069 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12070 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
12071 time = msg.time;
12072 pt = msg.pt;
12073 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
12074 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12075 ok( ret, "no message\n" );
12076 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12077 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12078 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12079 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
12080 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
12081 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 );
12082 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12083 ok( !ret, "got message %x\n", msg.message );
12084
12085 /* without PM_REMOVE */
12086 PostMessageW( hwnd, WM_CHAR, wch, 0 );
12087 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
12088 ok( ret, "no message\n" );
12089 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12090 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12091 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12092 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12093 ok( ret, "no message\n" );
12094 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12095 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12096 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12097 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
12098 ok( ret, "no message\n" );
12099 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12100 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12101 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12102 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12103 ok( ret, "no message\n" );
12104 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12105 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12106 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12107 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12108 ok( !ret, "got message %x\n", msg.message );
12109
12110 DestroyWindow(hwnd);
12111 DestroyWindow(hwnd2);
12112 }
12113
12114 static void test_unicode_wm_char(void)
12115 {
12116 HWND hwnd;
12117 MSG msg;
12118 struct message seq[2];
12119 HKL hkl_orig, hkl_greek;
12120 DWORD cp;
12121 LCID thread_locale;
12122
12123 hkl_orig = GetKeyboardLayout( 0 );
12124 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
12125 if (cp != 1252)
12126 {
12127 skip( "Default codepage %d\n", cp );
12128 return;
12129 }
12130
12131 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
12132 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
12133 {
12134 skip( "Unable to load Greek keyboard layout\n" );
12135 return;
12136 }
12137
12138 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
12139 100, 100, 200, 200, 0, 0, 0, NULL );
12140 flush_sequence();
12141
12142 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12143
12144 while (GetMessageW( &msg, hwnd, 0, 0 ))
12145 {
12146 if (!ignore_message( msg.message )) break;
12147 }
12148
12149 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12150 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12151 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
12152 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12153
12154 DispatchMessageW( &msg );
12155
12156 memset( seq, 0, sizeof(seq) );
12157 seq[0].message = WM_CHAR;
12158 seq[0].flags = sent|wparam;
12159 seq[0].wParam = 0x3b1;
12160
12161 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12162
12163 flush_sequence();
12164
12165 /* greek alpha -> 'a' in cp1252 */
12166 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12167
12168 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12169 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12170 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12171 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
12172 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12173
12174 DispatchMessageA( &msg );
12175
12176 seq[0].wParam = 0x61;
12177 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12178
12179 thread_locale = GetThreadLocale();
12180 ActivateKeyboardLayout( hkl_greek, 0 );
12181 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
12182 thread_locale, GetThreadLocale() );
12183
12184 flush_sequence();
12185
12186 /* greek alpha -> 0xe1 in cp1253 */
12187 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12188
12189 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12190 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12191 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12192 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
12193 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12194
12195 DispatchMessageA( &msg );
12196
12197 seq[0].wParam = 0x3b1;
12198 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12199
12200 DestroyWindow( hwnd );
12201 ActivateKeyboardLayout( hkl_orig, 0 );
12202 UnloadKeyboardLayout( hkl_greek );
12203 }
12204
12205 #define ID_LISTBOX 0x000f
12206
12207 static const struct message wm_lb_setcursel_0[] =
12208 {
12209 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
12210 { WM_CTLCOLORLISTBOX, sent|parent },
12211 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
12212 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12213 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12214 { 0 }
12215 };
12216 static const struct message wm_lb_setcursel_1[] =
12217 {
12218 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
12219 { WM_CTLCOLORLISTBOX, sent|parent },
12220 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
12221 { WM_CTLCOLORLISTBOX, sent|parent },
12222 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
12223 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
12224 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
12225 { 0 }
12226 };
12227 static const struct message wm_lb_setcursel_2[] =
12228 {
12229 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
12230 { WM_CTLCOLORLISTBOX, sent|parent },
12231 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
12232 { WM_CTLCOLORLISTBOX, sent|parent },
12233 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
12234 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12235 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12236 { 0 }
12237 };
12238 static const struct message wm_lb_click_0[] =
12239 {
12240 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
12241 { HCBT_SETFOCUS, hook },
12242 { WM_KILLFOCUS, sent|parent },
12243 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
12244 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
12245 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12246 { WM_SETFOCUS, sent|defwinproc },
12247
12248 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
12249 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
12250 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12251 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
12252 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
12253
12254 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
12255 { WM_CTLCOLORLISTBOX, sent|parent },
12256 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
12257 { WM_CTLCOLORLISTBOX, sent|parent },
12258 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
12259 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
12260
12261 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12262 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12263
12264 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
12265 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
12266 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
12267 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
12268 { 0 }
12269 };
12270 static const struct message wm_lb_deletestring[] =
12271 {
12272 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
12273 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
12274 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12275 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12276 { 0 }
12277 };
12278 static const struct message wm_lb_deletestring_reset[] =
12279 {
12280 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
12281 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
12282 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
12283 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12284 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12285 { 0 }
12286 };
12287
12288 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
12289
12290 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
12291
12292 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12293 {
12294 static LONG defwndproc_counter = 0;
12295 LRESULT ret;
12296 struct recvd_message msg;
12297
12298 /* do not log painting messages */
12299 if (message != WM_PAINT &&
12300 message != WM_NCPAINT &&
12301 message != WM_SYNCPAINT &&
12302 message != WM_ERASEBKGND &&
12303 message != WM_NCHITTEST &&
12304 message != WM_GETTEXT &&
12305 !ignore_message( message ))
12306 {
12307 msg.hwnd = hwnd;
12308 msg.message = message;
12309 msg.flags = sent|wparam|lparam;
12310 if (defwndproc_counter) msg.flags |= defwinproc;
12311 msg.wParam = wp;
12312 msg.lParam = lp;
12313 msg.descr = "listbox";
12314 add_message(&msg);
12315 }
12316
12317 defwndproc_counter++;
12318 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
12319 defwndproc_counter--;
12320
12321 return ret;
12322 }
12323
12324 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
12325 int caret_index, int top_index, int line)
12326 {
12327 LRESULT ret;
12328
12329 /* calling an orig proc helps to avoid unnecessary message logging */
12330 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
12331 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
12332 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
12333 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
12334 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
12335 ok_(__FILE__, line)(ret == caret_index ||
12336 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
12337 "expected caret index %d, got %ld\n", caret_index, ret);
12338 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
12339 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
12340 }
12341
12342 static void test_listbox_messages(void)
12343 {
12344 HWND parent, listbox;
12345 LRESULT ret;
12346
12347 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12348 100, 100, 200, 200, 0, 0, 0, NULL);
12349 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
12350 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
12351 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
12352 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
12353
12354 check_lb_state(listbox, 0, LB_ERR, 0, 0);
12355
12356 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
12357 ok(ret == 0, "expected 0, got %ld\n", ret);
12358 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
12359 ok(ret == 1, "expected 1, got %ld\n", ret);
12360 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
12361 ok(ret == 2, "expected 2, got %ld\n", ret);
12362
12363 check_lb_state(listbox, 3, LB_ERR, 0, 0);
12364
12365 flush_sequence();
12366
12367 log_all_parent_messages++;
12368
12369 trace("selecting item 0\n");
12370 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
12371 ok(ret == 0, "expected 0, got %ld\n", ret);
12372 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
12373 check_lb_state(listbox, 3, 0, 0, 0);
12374 flush_sequence();
12375
12376 trace("selecting item 1\n");
12377 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
12378 ok(ret == 1, "expected 1, got %ld\n", ret);
12379 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
12380 check_lb_state(listbox, 3, 1, 1, 0);
12381
12382 trace("selecting item 2\n");
12383 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
12384 ok(ret == 2, "expected 2, got %ld\n", ret);
12385 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
12386 check_lb_state(listbox, 3, 2, 2, 0);
12387
12388 trace("clicking on item 0\n");
12389 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
12390 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12391 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
12392 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12393 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
12394 check_lb_state(listbox, 3, 0, 0, 0);
12395 flush_sequence();
12396
12397 trace("deleting item 0\n");
12398 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12399 ok(ret == 2, "expected 2, got %ld\n", ret);
12400 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12401 check_lb_state(listbox, 2, -1, 0, 0);
12402 flush_sequence();
12403
12404 trace("deleting item 0\n");
12405 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12406 ok(ret == 1, "expected 1, got %ld\n", ret);
12407 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12408 check_lb_state(listbox, 1, -1, 0, 0);
12409 flush_sequence();
12410
12411 trace("deleting item 0\n");
12412 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12413 ok(ret == 0, "expected 0, got %ld\n", ret);
12414 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
12415 check_lb_state(listbox, 0, -1, 0, 0);
12416 flush_sequence();
12417
12418 trace("deleting item 0\n");
12419 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12420 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
12421 check_lb_state(listbox, 0, -1, 0, 0);
12422 flush_sequence();
12423
12424 log_all_parent_messages--;
12425
12426 DestroyWindow(listbox);
12427 DestroyWindow(parent);
12428 }
12429
12430 /*************************** Menu test ******************************/
12431 static const struct message wm_popup_menu_1[] =
12432 {
12433 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12434 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12435 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
12436 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
12437 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
12438 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
12439 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12440 { WM_INITMENU, sent|lparam, 0, 0 },
12441 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
12442 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
12443 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
12444 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
12445 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
12446 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12447 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
12448 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
12449 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12450 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12451 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12452 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
12453 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12454 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12455 { 0 }
12456 };
12457 static const struct message wm_popup_menu_2[] =
12458 {
12459 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12460 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12461 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12462 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12463 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12464 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12465 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12466 { WM_INITMENU, sent|lparam, 0, 0 },
12467 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12468 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12469 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12470 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12471 { HCBT_CREATEWND, hook },
12472 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12473 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12474 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12475 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12476 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12477 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12478 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12479 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12480 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12481 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12482 { HCBT_DESTROYWND, hook },
12483 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12484 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12485 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12486 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12487 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12488 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
12489 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12490 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12491 { 0 }
12492 };
12493 static const struct message wm_popup_menu_3[] =
12494 {
12495 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12496 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12497 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12498 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12499 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12500 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12501 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12502 { WM_INITMENU, sent|lparam, 0, 0 },
12503 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12504 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12505 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12506 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12507 { HCBT_CREATEWND, hook },
12508 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12509 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12510 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12511 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12512 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12513 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12514 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12515 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12516 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12517 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12518 { HCBT_DESTROYWND, hook },
12519 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12520 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12521 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12522 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12523 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12524 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
12525 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12526 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12527 { 0 }
12528 };
12529
12530 static const struct message wm_single_menu_item[] =
12531 {
12532 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12533 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12534 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
12535 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
12536 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
12537 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
12538 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12539 { WM_INITMENU, sent|lparam, 0, 0 },
12540 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
12541 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12542 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12543 { WM_MENUCOMMAND, sent },
12544 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
12545 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
12546 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
12547 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
12548
12549 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
12550 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
12551 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
12552 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
12553 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
12554 { 0 }
12555 };
12556
12557 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12558 {
12559 if (message == WM_ENTERIDLE ||
12560 message == WM_INITMENU ||
12561 message == WM_INITMENUPOPUP ||
12562 message == WM_MENUSELECT ||
12563 message == WM_PARENTNOTIFY ||
12564 message == WM_ENTERMENULOOP ||
12565 message == WM_EXITMENULOOP ||
12566 message == WM_UNINITMENUPOPUP ||
12567 message == WM_KEYDOWN ||
12568 message == WM_KEYUP ||
12569 message == WM_CHAR ||
12570 message == WM_SYSKEYDOWN ||
12571 message == WM_SYSKEYUP ||
12572 message == WM_SYSCHAR ||
12573 message == WM_COMMAND ||
12574 message == WM_MENUCOMMAND)
12575 {
12576 struct recvd_message msg;
12577
12578 msg.hwnd = hwnd;
12579 msg.message = message;
12580 msg.flags = sent|wparam|lparam;
12581 msg.wParam = wp;
12582 msg.lParam = lp;
12583 msg.descr = "parent_menu_proc";
12584 add_message(&msg);
12585 }
12586
12587 return DefWindowProcA(hwnd, message, wp, lp);
12588 }
12589
12590 static void set_menu_style(HMENU hmenu, DWORD style)
12591 {
12592 MENUINFO mi;
12593 BOOL ret;
12594
12595 mi.cbSize = sizeof(mi);
12596 mi.fMask = MIM_STYLE;
12597 mi.dwStyle = style;
12598 SetLastError(0xdeadbeef);
12599 ret = pSetMenuInfo(hmenu, &mi);
12600 ok(ret, "SetMenuInfo error %u\n", GetLastError());
12601 }
12602
12603 static DWORD get_menu_style(HMENU hmenu)
12604 {
12605 MENUINFO mi;
12606 BOOL ret;
12607
12608 mi.cbSize = sizeof(mi);
12609 mi.fMask = MIM_STYLE;
12610 mi.dwStyle = 0;
12611 SetLastError(0xdeadbeef);
12612 ret = pGetMenuInfo(hmenu, &mi);
12613 ok(ret, "GetMenuInfo error %u\n", GetLastError());
12614
12615 return mi.dwStyle;
12616 }
12617
12618 static void test_menu_messages(void)
12619 {
12620 MSG msg;
12621 WNDCLASSA cls;
12622 HMENU hmenu, hmenu_popup;
12623 HWND hwnd;
12624 DWORD style;
12625
12626 if (!pGetMenuInfo || !pSetMenuInfo)
12627 {
12628 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
12629 return;
12630 }
12631 cls.style = 0;
12632 cls.lpfnWndProc = parent_menu_proc;
12633 cls.cbClsExtra = 0;
12634 cls.cbWndExtra = 0;
12635 cls.hInstance = GetModuleHandleA(0);
12636 cls.hIcon = 0;
12637 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
12638 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
12639 cls.lpszMenuName = NULL;
12640 cls.lpszClassName = "TestMenuClass";
12641 UnregisterClassA(cls.lpszClassName, cls.hInstance);
12642 if (!RegisterClassA(&cls)) assert(0);
12643
12644 SetLastError(0xdeadbeef);
12645 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12646 100, 100, 200, 200, 0, 0, 0, NULL);
12647 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
12648
12649 SetLastError(0xdeadbeef);
12650 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
12651 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
12652
12653 SetMenu(hwnd, hmenu);
12654 SetForegroundWindow( hwnd );
12655 flush_events();
12656
12657 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
12658 style = get_menu_style(hmenu);
12659 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12660
12661 hmenu_popup = GetSubMenu(hmenu, 0);
12662 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12663 style = get_menu_style(hmenu_popup);
12664 ok(style == 0, "expected 0, got %u\n", style);
12665
12666 hmenu_popup = GetSubMenu(hmenu_popup, 0);
12667 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12668 style = get_menu_style(hmenu_popup);
12669 ok(style == 0, "expected 0, got %u\n", style);
12670
12671 /* Alt+E, Enter */
12672 trace("testing a popup menu command\n");
12673 flush_sequence();
12674 keybd_event(VK_MENU, 0, 0, 0);
12675 keybd_event('E', 0, 0, 0);
12676 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
12677 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12678 keybd_event(VK_RETURN, 0, 0, 0);
12679 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12680 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12681 {
12682 TranslateMessage(&msg);
12683 DispatchMessageA(&msg);
12684 }
12685 if (!sequence_cnt) /* we didn't get any message */
12686 {
12687 skip( "queuing key events not supported\n" );
12688 goto done;
12689 }
12690 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
12691 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
12692 {
12693 win_skip( "menu tracking through VK_MENU not supported\n" );
12694 goto done;
12695 }
12696 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
12697
12698 /* Alt+F, Right, Enter */
12699 trace("testing submenu of a popup menu command\n");
12700 flush_sequence();
12701 keybd_event(VK_MENU, 0, 0, 0);
12702 keybd_event('F', 0, 0, 0);
12703 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12704 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12705 keybd_event(VK_RIGHT, 0, 0, 0);
12706 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12707 keybd_event(VK_RETURN, 0, 0, 0);
12708 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12709 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12710 {
12711 TranslateMessage(&msg);
12712 DispatchMessageA(&msg);
12713 }
12714 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
12715
12716 trace("testing single menu item command\n");
12717 flush_sequence();
12718 keybd_event(VK_MENU, 0, 0, 0);
12719 keybd_event('Q', 0, 0, 0);
12720 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
12721 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12722 keybd_event(VK_ESCAPE, 0, 0, 0);
12723 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
12724 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12725 {
12726 TranslateMessage(&msg);
12727 DispatchMessageA(&msg);
12728 }
12729 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
12730
12731 set_menu_style(hmenu, 0);
12732 style = get_menu_style(hmenu);
12733 ok(style == 0, "expected 0, got %u\n", style);
12734
12735 hmenu_popup = GetSubMenu(hmenu, 0);
12736 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12737 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
12738 style = get_menu_style(hmenu_popup);
12739 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12740
12741 hmenu_popup = GetSubMenu(hmenu_popup, 0);
12742 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12743 style = get_menu_style(hmenu_popup);
12744 ok(style == 0, "expected 0, got %u\n", style);
12745
12746 /* Alt+F, Right, Enter */
12747 trace("testing submenu of a popup menu command\n");
12748 flush_sequence();
12749 keybd_event(VK_MENU, 0, 0, 0);
12750 keybd_event('F', 0, 0, 0);
12751 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12752 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12753 keybd_event(VK_RIGHT, 0, 0, 0);
12754 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12755 keybd_event(VK_RETURN, 0, 0, 0);
12756 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12757 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12758 {
12759 TranslateMessage(&msg);
12760 DispatchMessageA(&msg);
12761 }
12762 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
12763
12764 done:
12765 DestroyWindow(hwnd);
12766 DestroyMenu(hmenu);
12767 }
12768
12769
12770 static void test_paintingloop(void)
12771 {
12772 HWND hwnd;
12773
12774 paint_loop_done = FALSE;
12775 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
12776 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
12777 100, 100, 100, 100, 0, 0, 0, NULL );
12778 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
12779 ShowWindow(hwnd,SW_NORMAL);
12780 SetFocus(hwnd);
12781
12782 while (!paint_loop_done)
12783 {
12784 MSG msg;
12785 if (PeekMessageA(&msg, 0, 0, 0, 1))
12786 {
12787 TranslateMessage(&msg);
12788 DispatchMessageA(&msg);
12789 }
12790 }
12791 DestroyWindow(hwnd);
12792 }
12793
12794 static void test_defwinproc(void)
12795 {
12796 HWND hwnd;
12797 MSG msg;
12798 BOOL gotwmquit = FALSE;
12799 hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
12800 assert(hwnd);
12801 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
12802 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
12803 if( msg.message == WM_QUIT) gotwmquit = TRUE;
12804 DispatchMessageA( &msg );
12805 }
12806 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
12807 DestroyWindow( hwnd);
12808 }
12809
12810 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
12811 static void clear_clipboard_(int line, HWND hWnd)
12812 {
12813 BOOL succ;
12814 succ = OpenClipboard(hWnd);
12815 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
12816 succ = EmptyClipboard();
12817 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
12818 succ = CloseClipboard();
12819 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
12820 }
12821
12822 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
12823 static void expect_HWND_(int line, HWND expected, HWND got)
12824 {
12825 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
12826 }
12827
12828 static WNDPROC pOldViewerProc;
12829
12830 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
12831 {
12832 static BOOL recursion_guard;
12833
12834 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
12835 {
12836 recursion_guard = TRUE;
12837 clear_clipboard(hWnd);
12838 recursion_guard = FALSE;
12839 }
12840 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
12841 }
12842
12843 static void test_clipboard_viewers(void)
12844 {
12845 static struct message wm_change_cb_chain[] =
12846 {
12847 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
12848 { 0 }
12849 };
12850 static const struct message wm_clipboard_destroyed[] =
12851 {
12852 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12853 { 0 }
12854 };
12855 static struct message wm_clipboard_changed[] =
12856 {
12857 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12858 { 0 }
12859 };
12860 static struct message wm_clipboard_changed_and_owned[] =
12861 {
12862 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12863 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12864 { 0 }
12865 };
12866
12867 HINSTANCE hInst = GetModuleHandleA(NULL);
12868 HWND hWnd1, hWnd2, hWnd3;
12869 HWND hOrigViewer;
12870 HWND hRet;
12871
12872 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
12873 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12874 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12875 GetDesktopWindow(), NULL, hInst, NULL);
12876 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
12877 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12878 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12879 GetDesktopWindow(), NULL, hInst, NULL);
12880 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
12881 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12882 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12883 GetDesktopWindow(), NULL, hInst, NULL);
12884 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
12885 assert(hWnd1 && hWnd2 && hWnd3);
12886
12887 flush_sequence();
12888
12889 /* Test getting the clipboard viewer and setting the viewer to NULL. */
12890 hOrigViewer = GetClipboardViewer();
12891 hRet = SetClipboardViewer(NULL);
12892 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
12893 expect_HWND(hOrigViewer, hRet);
12894 expect_HWND(NULL, GetClipboardViewer());
12895
12896 /* Test registering hWnd1 as a viewer. */
12897 hRet = SetClipboardViewer(hWnd1);
12898 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12899 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
12900 expect_HWND(NULL, hRet);
12901 expect_HWND(hWnd1, GetClipboardViewer());
12902
12903 /* Test that changing the clipboard actually refreshes the registered viewer. */
12904 clear_clipboard(hWnd1);
12905 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12906 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
12907
12908 /* Again, but with different owner. */
12909 clear_clipboard(hWnd2);
12910 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
12911 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
12912
12913 /* Test re-registering same window. */
12914 hRet = SetClipboardViewer(hWnd1);
12915 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12916 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
12917 expect_HWND(hWnd1, hRet);
12918 expect_HWND(hWnd1, GetClipboardViewer());
12919
12920 /* Test ChangeClipboardChain. */
12921 ChangeClipboardChain(hWnd2, hWnd3);
12922 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12923 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
12924 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
12925 expect_HWND(hWnd1, GetClipboardViewer());
12926
12927 ChangeClipboardChain(hWnd2, NULL);
12928 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12929 wm_change_cb_chain[0].lParam = 0;
12930 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
12931 expect_HWND(hWnd1, GetClipboardViewer());
12932
12933 ChangeClipboardChain(NULL, hWnd2);
12934 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
12935 expect_HWND(hWnd1, GetClipboardViewer());
12936
12937 /* Actually change clipboard viewer with ChangeClipboardChain. */
12938 ChangeClipboardChain(hWnd1, hWnd2);
12939 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
12940 expect_HWND(hWnd2, GetClipboardViewer());
12941
12942 /* Test that no refresh messages are sent when viewer has unregistered. */
12943 clear_clipboard(hWnd2);
12944 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
12945
12946 /* Register hWnd1 again. */
12947 ChangeClipboardChain(hWnd2, hWnd1);
12948 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
12949 expect_HWND(hWnd1, GetClipboardViewer());
12950
12951 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
12952 * changes the clipboard. When this happens, the system shouldn't send
12953 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
12954 */
12955 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
12956 clear_clipboard(hWnd2);
12957 /* The clipboard owner is changed in recursive_viewer_proc: */
12958 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
12959 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
12960
12961 /* Test unregistering. */
12962 ChangeClipboardChain(hWnd1, NULL);
12963 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
12964 expect_HWND(NULL, GetClipboardViewer());
12965
12966 clear_clipboard(hWnd1);
12967 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
12968
12969 DestroyWindow(hWnd1);
12970 DestroyWindow(hWnd2);
12971 DestroyWindow(hWnd3);
12972 SetClipboardViewer(hOrigViewer);
12973 }
12974
12975 static void test_PostMessage(void)
12976 {
12977 static const struct
12978 {
12979 HWND hwnd;
12980 BOOL ret;
12981 } data[] =
12982 {
12983 { HWND_TOP /* 0 */, TRUE },
12984 { HWND_BROADCAST, TRUE },
12985 { HWND_BOTTOM, TRUE },
12986 { HWND_TOPMOST, TRUE },
12987 { HWND_NOTOPMOST, FALSE },
12988 { HWND_MESSAGE, FALSE },
12989 { (HWND)0xdeadbeef, FALSE }
12990 };
12991 int i;
12992 HWND hwnd;
12993 BOOL ret;
12994 MSG msg;
12995 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
12996
12997 SetLastError(0xdeadbeef);
12998 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12999 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
13000 {
13001 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
13002 return;
13003 }
13004 assert(hwnd);
13005
13006 flush_events();
13007
13008 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
13009 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
13010
13011 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
13012 {
13013 memset(&msg, 0xab, sizeof(msg));
13014 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
13015 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
13016 if (data[i].ret)
13017 {
13018 if (data[i].hwnd)
13019 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
13020 msg.wParam == 0x5678 && msg.lParam == 0x1234,
13021 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
13022 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
13023 else
13024 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
13025 msg.wParam == 0x1234 && msg.lParam == 0x5678,
13026 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
13027 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
13028 }
13029 }
13030
13031 DestroyWindow(hwnd);
13032 flush_events();
13033 }
13034
13035 static const struct
13036 {
13037 DWORD exp, broken;
13038 BOOL todo;
13039 } wait_idle_expect[] =
13040 {
13041 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13042 { WAIT_TIMEOUT, 0, FALSE },
13043 { WAIT_TIMEOUT, 0, FALSE },
13044 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13045 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13046 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
13047 { WAIT_TIMEOUT, 0, FALSE },
13048 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13049 { 0, 0, FALSE },
13050 { 0, 0, FALSE },
13051 /* 10 */ { 0, 0, FALSE },
13052 { 0, 0, FALSE },
13053 { 0, WAIT_TIMEOUT, FALSE },
13054 { 0, 0, FALSE },
13055 { 0, 0, FALSE },
13056 /* 15 */ { 0, 0, FALSE },
13057 { WAIT_TIMEOUT, 0, FALSE },
13058 { WAIT_TIMEOUT, 0, FALSE },
13059 { WAIT_TIMEOUT, 0, FALSE },
13060 { WAIT_TIMEOUT, 0, FALSE },
13061 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
13062 };
13063
13064 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
13065 {
13066 MSG msg;
13067
13068 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13069 Sleep( 200 );
13070 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13071 return 0;
13072 }
13073
13074 static void do_wait_idle_child( int arg )
13075 {
13076 WNDCLASSA cls;
13077 MSG msg;
13078 HWND hwnd = 0;
13079 HANDLE thread;
13080 DWORD id;
13081 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
13082 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
13083
13084 memset( &cls, 0, sizeof(cls) );
13085 cls.lpfnWndProc = DefWindowProcA;
13086 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
13087 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
13088 cls.lpszClassName = "TestClass";
13089 RegisterClassA( &cls );
13090
13091 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
13092
13093 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
13094 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
13095
13096 switch (arg)
13097 {
13098 case 0:
13099 SetEvent( start_event );
13100 break;
13101 case 1:
13102 SetEvent( start_event );
13103 Sleep( 200 );
13104 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13105 break;
13106 case 2:
13107 SetEvent( start_event );
13108 Sleep( 200 );
13109 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13110 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
13111 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13112 break;
13113 case 3:
13114 SetEvent( start_event );
13115 Sleep( 200 );
13116 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
13117 break;
13118 case 4:
13119 SetEvent( start_event );
13120 Sleep( 200 );
13121 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13122 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
13123 break;
13124 case 5:
13125 SetEvent( start_event );
13126 Sleep( 200 );
13127 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13128 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13129 break;
13130 case 6:
13131 SetEvent( start_event );
13132 Sleep( 200 );
13133 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13134 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
13135 {
13136 GetMessageA( &msg, 0, 0, 0 );
13137 DispatchMessageA( &msg );
13138 }
13139 break;
13140 case 7:
13141 SetEvent( start_event );
13142 Sleep( 200 );
13143 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13144 SetTimer( hwnd, 3, 1, NULL );
13145 Sleep( 200 );
13146 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
13147 break;
13148 case 8:
13149 SetEvent( start_event );
13150 Sleep( 200 );
13151 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13152 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13153 break;
13154 case 9:
13155 SetEvent( start_event );
13156 Sleep( 200 );
13157 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13158 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13159 for (;;) GetMessageA( &msg, 0, 0, 0 );
13160 break;
13161 case 10:
13162 SetEvent( start_event );
13163 Sleep( 200 );
13164 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13165 SetTimer( hwnd, 3, 1, NULL );
13166 Sleep( 200 );
13167 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13168 break;
13169 case 11:
13170 SetEvent( start_event );
13171 Sleep( 200 );
13172 return; /* exiting the process makes WaitForInputIdle return success too */
13173 case 12:
13174 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13175 Sleep( 200 );
13176 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13177 SetEvent( start_event );
13178 break;
13179 case 13:
13180 SetEvent( start_event );
13181 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13182 Sleep( 200 );
13183 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
13184 WaitForSingleObject( thread, 10000 );
13185 CloseHandle( thread );
13186 break;
13187 case 14:
13188 SetEvent( start_event );
13189 Sleep( 200 );
13190 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
13191 break;
13192 case 15:
13193 SetEvent( start_event );
13194 Sleep( 200 );
13195 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
13196 break;
13197 case 16:
13198 SetEvent( start_event );
13199 Sleep( 200 );
13200 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
13201 break;
13202 case 17:
13203 SetEvent( start_event );
13204 Sleep( 200 );
13205 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
13206 break;
13207 case 18:
13208 SetEvent( start_event );
13209 Sleep( 200 );
13210 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
13211 break;
13212 case 19:
13213 SetEvent( start_event );
13214 Sleep( 200 );
13215 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
13216 break;
13217 case 20:
13218 SetEvent( start_event );
13219 Sleep( 200 );
13220 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
13221 break;
13222 }
13223 WaitForSingleObject( end_event, 2000 );
13224 CloseHandle( start_event );
13225 CloseHandle( end_event );
13226 if (hwnd) DestroyWindow( hwnd );
13227 }
13228
13229 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
13230 {
13231 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
13232 return DefWindowProcA( hwnd, msg, wp, lp );
13233 }
13234
13235 static DWORD CALLBACK wait_idle_thread( void *arg )
13236 {
13237 WNDCLASSA cls;
13238 MSG msg;
13239 HWND hwnd;
13240
13241 memset( &cls, 0, sizeof(cls) );
13242 cls.lpfnWndProc = wait_idle_proc;
13243 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
13244 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
13245 cls.lpszClassName = "TestClass";
13246 RegisterClassA( &cls );
13247
13248 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
13249 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
13250 DestroyWindow(hwnd);
13251 return 0;
13252 }
13253
13254 static void test_WaitForInputIdle( char *argv0 )
13255 {
13256 char path[MAX_PATH];
13257 PROCESS_INFORMATION pi;
13258 STARTUPINFOA startup;
13259 BOOL ret;
13260 HANDLE start_event, end_event, thread;
13261 unsigned int i;
13262 DWORD id;
13263 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
13264 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
13265 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
13266
13267 if (console_app) /* build the test with -mwindows for better coverage */
13268 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
13269
13270 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
13271 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
13272 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
13273 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
13274
13275 memset( &startup, 0, sizeof(startup) );
13276 startup.cb = sizeof(startup);
13277 startup.dwFlags = STARTF_USESHOWWINDOW;
13278 startup.wShowWindow = SW_SHOWNORMAL;
13279
13280 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
13281
13282 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
13283 {
13284 ResetEvent( start_event );
13285 ResetEvent( end_event );
13286 sprintf( path, "%s msg %u", argv0, i );
13287 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
13288 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
13289 if (ret)
13290 {
13291 ret = WaitForSingleObject( start_event, 5000 );
13292 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
13293 if (ret == WAIT_OBJECT_0)
13294 {
13295 ret = WaitForInputIdle( pi.hProcess, 1000 );
13296 if (ret == WAIT_FAILED)
13297 ok( console_app ||
13298 ret == wait_idle_expect[i].exp ||
13299 broken(ret == wait_idle_expect[i].broken),
13300 "%u: WaitForInputIdle error %08x expected %08x\n",
13301 i, ret, wait_idle_expect[i].exp );
13302 else if (wait_idle_expect[i].todo)
13303 todo_wine
13304 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
13305 "%u: WaitForInputIdle error %08x expected %08x\n",
13306 i, ret, wait_idle_expect[i].exp );
13307 else
13308 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
13309 "%u: WaitForInputIdle error %08x expected %08x\n",
13310 i, ret, wait_idle_expect[i].exp );
13311 SetEvent( end_event );
13312 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
13313 }
13314 TerminateProcess( pi.hProcess, 0 ); /* just in case */
13315 winetest_wait_child_process( pi.hProcess );
13316 ret = WaitForInputIdle( pi.hProcess, 100 );
13317 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
13318 CloseHandle( pi.hProcess );
13319 CloseHandle( pi.hThread );
13320 }
13321 }
13322 CloseHandle( start_event );
13323 PostThreadMessageA( id, WM_QUIT, 0, 0 );
13324 WaitForSingleObject( thread, 10000 );
13325 CloseHandle( thread );
13326 }
13327
13328 static const struct message WmSetParentSeq_1[] = {
13329 { WM_SHOWWINDOW, sent|wparam, 0 },
13330 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13331 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
13332 { WM_CHILDACTIVATE, sent },
13333 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
13334 { WM_MOVE, sent|defwinproc|wparam, 0 },
13335 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13336 { WM_SHOWWINDOW, sent|wparam, 1 },
13337 { 0 }
13338 };
13339
13340 static const struct message WmSetParentSeq_2[] = {
13341 { WM_SHOWWINDOW, sent|wparam, 0 },
13342 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13343 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
13344 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13345 { HCBT_SETFOCUS, hook|optional },
13346 { WM_NCACTIVATE, sent|wparam|optional, 0 },
13347 { WM_ACTIVATE, sent|wparam|optional, 0 },
13348 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13349 { WM_KILLFOCUS, sent|wparam, 0 },
13350 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13351 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
13352 { HCBT_ACTIVATE, hook|optional },
13353 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
13354 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13355 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13356 { WM_ACTIVATE, sent|wparam|optional, 1 },
13357 { HCBT_SETFOCUS, hook|optional },
13358 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13359 { WM_SETFOCUS, sent|optional|defwinproc },
13360 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
13361 { WM_MOVE, sent|defwinproc|wparam, 0 },
13362 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13363 { WM_SHOWWINDOW, sent|wparam, 1 },
13364 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13365 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
13366 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13367 { 0 }
13368 };
13369
13370
13371 static void test_SetParent(void)
13372 {
13373 HWND parent1, parent2, child, popup;
13374 RECT rc, rc_old;
13375
13376 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13377 100, 100, 200, 200, 0, 0, 0, NULL);
13378 ok(parent1 != 0, "Failed to create parent1 window\n");
13379
13380 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13381 400, 100, 200, 200, 0, 0, 0, NULL);
13382 ok(parent2 != 0, "Failed to create parent2 window\n");
13383
13384 /* WS_CHILD window */
13385 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
13386 10, 10, 150, 150, parent1, 0, 0, NULL);
13387 ok(child != 0, "Failed to create child window\n");
13388
13389 GetWindowRect(parent1, &rc);
13390 trace("parent1 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13391 GetWindowRect(child, &rc_old);
13392 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
13393 trace("child (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13394
13395 flush_sequence();
13396
13397 SetParent(child, parent2);
13398 flush_events();
13399 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
13400
13401 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13402 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
13403
13404 GetWindowRect(parent2, &rc);
13405 trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13406 GetWindowRect(child, &rc);
13407 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
13408 trace("child (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13409
13410 ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13411 rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13412 rc.left, rc.top, rc.right, rc.bottom );
13413
13414 /* WS_POPUP window */
13415 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
13416 20, 20, 100, 100, 0, 0, 0, NULL);
13417 ok(popup != 0, "Failed to create popup window\n");
13418
13419 GetWindowRect(popup, &rc_old);
13420 trace("popup (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13421
13422 flush_sequence();
13423
13424 SetParent(popup, child);
13425 flush_events();
13426 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
13427
13428 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13429 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
13430
13431 GetWindowRect(child, &rc);
13432 trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13433 GetWindowRect(popup, &rc);
13434 MapWindowPoints(0, child, (POINT *)&rc, 2);
13435 trace("popup (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13436
13437 ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13438 rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13439 rc.left, rc.top, rc.right, rc.bottom );
13440
13441 DestroyWindow(popup);
13442 DestroyWindow(child);
13443 DestroyWindow(parent1);
13444 DestroyWindow(parent2);
13445
13446 flush_sequence();
13447 }
13448
13449 static const struct message WmKeyReleaseOnly[] = {
13450 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
13451 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
13452 { 0 }
13453 };
13454 static const struct message WmKeyPressNormal[] = {
13455 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
13456 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
13457 { 0 }
13458 };
13459 static const struct message WmKeyPressRepeat[] = {
13460 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
13461 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
13462 { 0 }
13463 };
13464 static const struct message WmKeyReleaseNormal[] = {
13465 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
13466 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
13467 { 0 }
13468 };
13469
13470 static void test_keyflags(void)
13471 {
13472 HWND test_window;
13473 SHORT key_state;
13474 BYTE keyboard_state[256];
13475 MSG msg;
13476
13477 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13478 100, 100, 200, 200, 0, 0, 0, NULL);
13479
13480 flush_events();
13481 flush_sequence();
13482
13483 /* keyup without a keydown */
13484 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13485 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13486 DispatchMessageA(&msg);
13487 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
13488
13489 key_state = GetAsyncKeyState(0x41);
13490 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13491
13492 key_state = GetKeyState(0x41);
13493 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13494
13495 /* keydown */
13496 keybd_event(0x41, 0, 0, 0);
13497 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13498 DispatchMessageA(&msg);
13499 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
13500
13501 key_state = GetAsyncKeyState(0x41);
13502 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13503
13504 key_state = GetKeyState(0x41);
13505 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13506
13507 /* keydown repeat */
13508 keybd_event(0x41, 0, 0, 0);
13509 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13510 DispatchMessageA(&msg);
13511 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
13512
13513 key_state = GetAsyncKeyState(0x41);
13514 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13515
13516 key_state = GetKeyState(0x41);
13517 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13518
13519 /* keyup */
13520 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13521 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13522 DispatchMessageA(&msg);
13523 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
13524
13525 key_state = GetAsyncKeyState(0x41);
13526 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13527
13528 key_state = GetKeyState(0x41);
13529 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13530
13531 /* set the key state in this thread */
13532 GetKeyboardState(keyboard_state);
13533 keyboard_state[0x41] = 0x80;
13534 SetKeyboardState(keyboard_state);
13535
13536 key_state = GetAsyncKeyState(0x41);
13537 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13538
13539 /* keydown */
13540 keybd_event(0x41, 0, 0, 0);
13541 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13542 DispatchMessageA(&msg);
13543 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
13544
13545 key_state = GetAsyncKeyState(0x41);
13546 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13547
13548 key_state = GetKeyState(0x41);
13549 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13550
13551 /* clear the key state in this thread */
13552 GetKeyboardState(keyboard_state);
13553 keyboard_state[0x41] = 0;
13554 SetKeyboardState(keyboard_state);
13555
13556 key_state = GetAsyncKeyState(0x41);
13557 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13558
13559 /* keyup */
13560 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13561 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13562 DispatchMessageA(&msg);
13563 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
13564
13565 key_state = GetAsyncKeyState(0x41);
13566 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13567
13568 key_state = GetKeyState(0x41);
13569 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13570
13571 DestroyWindow(test_window);
13572 flush_sequence();
13573 }
13574
13575 static const struct message WmHotkeyPressLWIN[] = {
13576 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13577 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13578 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13579 { 0 }
13580 };
13581 static const struct message WmHotkeyPress[] = {
13582 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13583 { WM_HOTKEY, sent|wparam, 5 },
13584 { 0 }
13585 };
13586 static const struct message WmHotkeyRelease[] = {
13587 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13588 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
13589 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
13590 { 0 }
13591 };
13592 static const struct message WmHotkeyReleaseLWIN[] = {
13593 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13594 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13595 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13596 { 0 }
13597 };
13598 static const struct message WmHotkeyCombined[] = {
13599 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13600 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13601 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13602 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13603 { WM_APP, sent, 0, 0 },
13604 { WM_HOTKEY, sent|wparam, 5 },
13605 { WM_APP+1, sent, 0, 0 },
13606 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13607 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13608 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13609 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13610 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13611 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13612 { 0 }
13613 };
13614 static const struct message WmHotkeyPrevious[] = {
13615 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13616 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13617 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13618 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13619 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13620 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13621 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
13622 { WM_KEYDOWN, sent|lparam, 0, 1 },
13623 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
13624 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
13625 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13626 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13627 { 0 }
13628 };
13629 static const struct message WmHotkeyNew[] = {
13630 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13631 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13632 { WM_HOTKEY, sent|wparam, 5 },
13633 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13634 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13635 { 0 }
13636 };
13637
13638 static int hotkey_letter;
13639
13640 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
13641 {
13642 struct recvd_message msg;
13643
13644 if (nCode == HC_ACTION)
13645 {
13646 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
13647
13648 msg.hwnd = 0;
13649 msg.message = wParam;
13650 msg.flags = kbd_hook|wparam|lparam;
13651 msg.wParam = kdbhookstruct->vkCode;
13652 msg.lParam = kdbhookstruct->flags;
13653 msg.descr = "KeyboardHookProc";
13654 add_message(&msg);
13655
13656 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
13657 {
13658 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
13659 "unexpected keycode %x\n", kdbhookstruct->vkCode);
13660 }
13661 }
13662
13663 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
13664 }
13665
13666 static void test_hotkey(void)
13667 {
13668 HWND test_window, taskbar_window;
13669 BOOL ret;
13670 MSG msg;
13671 DWORD queue_status;
13672 SHORT key_state;
13673
13674 SetLastError(0xdeadbeef);
13675 ret = UnregisterHotKey(NULL, 0);
13676 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13677 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13678 "unexpected error %d\n", GetLastError());
13679
13680 if (ret == TRUE)
13681 {
13682 skip("hotkeys not supported\n");
13683 return;
13684 }
13685
13686 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13687 100, 100, 200, 200, 0, 0, 0, NULL);
13688
13689 flush_sequence();
13690
13691 SetLastError(0xdeadbeef);
13692 ret = UnregisterHotKey(test_window, 0);
13693 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13694 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13695 "unexpected error %d\n", GetLastError());
13696
13697 /* Search for a Windows Key + letter combination that hasn't been registered */
13698 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
13699 {
13700 SetLastError(0xdeadbeef);
13701 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13702
13703 if (ret == TRUE)
13704 {
13705 break;
13706 }
13707 else
13708 {
13709 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13710 "unexpected error %d\n", GetLastError());
13711 }
13712 }
13713
13714 if (hotkey_letter == 0x52)
13715 {
13716 ok(0, "Couldn't find any free Windows Key + letter combination\n");
13717 goto end;
13718 }
13719
13720 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
13721 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
13722
13723 /* Same key combination, different id */
13724 SetLastError(0xdeadbeef);
13725 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
13726 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13727 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13728 "unexpected error %d\n", GetLastError());
13729
13730 /* Same key combination, different window */
13731 SetLastError(0xdeadbeef);
13732 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13733 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13734 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13735 "unexpected error %d\n", GetLastError());
13736
13737 /* Register the same hotkey twice */
13738 SetLastError(0xdeadbeef);
13739 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13740 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13741 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13742 "unexpected error %d\n", GetLastError());
13743
13744 /* Window on another thread */
13745 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
13746 if (!taskbar_window)
13747 {
13748 skip("no taskbar?\n");
13749 }
13750 else
13751 {
13752 SetLastError(0xdeadbeef);
13753 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
13754 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13755 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
13756 "unexpected error %d\n", GetLastError());
13757 }
13758
13759 /* Inject the appropriate key sequence */
13760 keybd_event(VK_LWIN, 0, 0, 0);
13761 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13762 DispatchMessageA(&msg);
13763 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
13764
13765 keybd_event(hotkey_letter, 0, 0, 0);
13766 queue_status = GetQueueStatus(QS_HOTKEY);
13767 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13768 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13769 {
13770 if (msg.message == WM_HOTKEY)
13771 {
13772 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13773 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13774 }
13775 DispatchMessageA(&msg);
13776 }
13777 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
13778
13779 queue_status = GetQueueStatus(QS_HOTKEY);
13780 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
13781
13782 key_state = GetAsyncKeyState(hotkey_letter);
13783 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13784
13785 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13786 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13787 DispatchMessageA(&msg);
13788 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
13789
13790 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13791 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13792 DispatchMessageA(&msg);
13793 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
13794
13795 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
13796 PostMessageA(test_window, WM_HOTKEY, 0, 0);
13797 queue_status = GetQueueStatus(QS_HOTKEY);
13798 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13799 queue_status = GetQueueStatus(QS_POSTMESSAGE);
13800 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
13801 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13802 DispatchMessageA(&msg);
13803 flush_sequence();
13804
13805 /* Send and process all messages at once */
13806 PostMessageA(test_window, WM_APP, 0, 0);
13807 keybd_event(VK_LWIN, 0, 0, 0);
13808 keybd_event(hotkey_letter, 0, 0, 0);
13809 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13810 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13811
13812 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13813 {
13814 if (msg.message == WM_HOTKEY)
13815 {
13816 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13817 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13818 }
13819 DispatchMessageA(&msg);
13820 }
13821 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
13822
13823 /* Register same hwnd/id with different key combination */
13824 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
13825 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13826
13827 /* Previous key combination does not work */
13828 keybd_event(VK_LWIN, 0, 0, 0);
13829 keybd_event(hotkey_letter, 0, 0, 0);
13830 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13831 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13832
13833 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13834 DispatchMessageA(&msg);
13835 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
13836
13837 /* New key combination works */
13838 keybd_event(hotkey_letter, 0, 0, 0);
13839 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13840
13841 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13842 {
13843 if (msg.message == WM_HOTKEY)
13844 {
13845 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13846 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13847 }
13848 DispatchMessageA(&msg);
13849 }
13850 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
13851
13852 /* Unregister hotkey properly */
13853 ret = UnregisterHotKey(test_window, 5);
13854 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13855
13856 /* Unregister hotkey again */
13857 SetLastError(0xdeadbeef);
13858 ret = UnregisterHotKey(test_window, 5);
13859 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13860 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13861 "unexpected error %d\n", GetLastError());
13862
13863 /* Register thread hotkey */
13864 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13865 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13866
13867 /* Inject the appropriate key sequence */
13868 keybd_event(VK_LWIN, 0, 0, 0);
13869 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13870 {
13871 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13872 DispatchMessageA(&msg);
13873 }
13874 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
13875
13876 keybd_event(hotkey_letter, 0, 0, 0);
13877 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13878 {
13879 if (msg.message == WM_HOTKEY)
13880 {
13881 struct recvd_message message;
13882 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
13883 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13884 message.message = msg.message;
13885 message.flags = sent|wparam|lparam;
13886 message.wParam = msg.wParam;
13887 message.lParam = msg.lParam;
13888 message.descr = "test_hotkey thread message";
13889 add_message(&message);
13890 }
13891 else
13892 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13893 DispatchMessageA(&msg);
13894 }
13895 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
13896
13897 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13898 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13899 {
13900 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13901 DispatchMessageA(&msg);
13902 }
13903 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
13904
13905 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13906 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13907 {
13908 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13909 DispatchMessageA(&msg);
13910 }
13911 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
13912
13913 /* Unregister thread hotkey */
13914 ret = UnregisterHotKey(NULL, 5);
13915 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13916
13917 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
13918 hKBD_hook = NULL;
13919
13920 end:
13921 UnregisterHotKey(NULL, 5);
13922 UnregisterHotKey(test_window, 5);
13923 DestroyWindow(test_window);
13924 flush_sequence();
13925 }
13926
13927
13928 static const struct message WmSetFocus_1[] = {
13929 { HCBT_SETFOCUS, hook }, /* child */
13930 { HCBT_ACTIVATE, hook }, /* parent */
13931 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
13932 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
13933 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
13934 { WM_NCACTIVATE, sent|parent },
13935 { WM_GETTEXT, sent|defwinproc|parent|optional },
13936 { WM_GETTEXT, sent|defwinproc|parent|optional },
13937 { WM_ACTIVATE, sent|wparam|parent, 1 },
13938 { HCBT_SETFOCUS, hook }, /* parent */
13939 { WM_SETFOCUS, sent|defwinproc|parent },
13940 { WM_KILLFOCUS, sent|parent },
13941 { WM_SETFOCUS, sent },
13942 { 0 }
13943 };
13944 static const struct message WmSetFocus_2[] = {
13945 { HCBT_SETFOCUS, hook }, /* parent */
13946 { WM_KILLFOCUS, sent },
13947 { WM_SETFOCUS, sent|parent },
13948 { 0 }
13949 };
13950 static const struct message WmSetFocus_3[] = {
13951 { HCBT_SETFOCUS, hook }, /* child */
13952 { 0 }
13953 };
13954 static const struct message WmSetFocus_4[] = {
13955 { 0 }
13956 };
13957
13958 static void test_SetFocus(void)
13959 {
13960 HWND parent, old_parent, child, old_focus, old_active;
13961 MSG msg;
13962 struct wnd_event wnd_event;
13963 HANDLE hthread;
13964 DWORD ret, tid;
13965
13966 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
13967 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
13968 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
13969 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
13970 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
13971 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
13972 CloseHandle(wnd_event.start_event);
13973
13974 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13975 0, 0, 0, 0, 0, 0, 0, NULL);
13976 ok(parent != 0, "failed to create parent window\n");
13977 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
13978 0, 0, 0, 0, parent, 0, 0, NULL);
13979 ok(child != 0, "failed to create child window\n");
13980
13981 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
13982
13983 SetFocus(0);
13984 SetActiveWindow(0);
13985
13986 flush_events();
13987 flush_sequence();
13988
13989 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13990 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13991
13992 log_all_parent_messages++;
13993
13994 old_focus = SetFocus(child);
13995 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13996 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
13997 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13998 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13999 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
14000
14001 old_focus = SetFocus(parent);
14002 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14003 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
14004 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
14005 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14006 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14007
14008 SetLastError(0xdeadbeef);
14009 old_focus = SetFocus((HWND)0xdeadbeef);
14010 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14011 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
14012 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14013 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
14014 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14015 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14016 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14017
14018 SetLastError(0xdeadbeef);
14019 old_focus = SetFocus(GetDesktopWindow());
14020 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
14021 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
14022 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14023 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
14024 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14025 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14026 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14027
14028 SetLastError(0xdeadbeef);
14029 old_focus = SetFocus(wnd_event.hwnd);
14030 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
14031 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
14032 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14033 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
14034 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14035 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14036 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14037
14038 SetLastError(0xdeadbeef);
14039 old_active = SetActiveWindow((HWND)0xdeadbeef);
14040 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14041 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
14042 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14043 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
14044 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
14045 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14046 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14047
14048 SetLastError(0xdeadbeef);
14049 old_active = SetActiveWindow(GetDesktopWindow());
14050 todo_wine
14051 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
14052 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14053 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
14054 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
14055 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14056 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14057
14058 SetLastError(0xdeadbeef);
14059 old_active = SetActiveWindow(wnd_event.hwnd);
14060 todo_wine
14061 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
14062 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14063 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
14064 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
14065 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14066 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14067
14068 SetLastError(0xdeadbeef);
14069 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
14070 ok(ret, "AttachThreadInput error %d\n", GetLastError());
14071
14072 todo_wine {
14073 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14074 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14075 }
14076 flush_events();
14077 flush_sequence();
14078
14079 old_focus = SetFocus(wnd_event.hwnd);
14080 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14081 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
14082 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
14083 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
14084
14085 old_focus = SetFocus(parent);
14086 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14087 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
14088 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14089 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14090
14091 flush_events();
14092 flush_sequence();
14093
14094 old_active = SetActiveWindow(wnd_event.hwnd);
14095 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14096 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
14097 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
14098 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
14099
14100 SetLastError(0xdeadbeef);
14101 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
14102 ok(ret, "AttachThreadInput error %d\n", GetLastError());
14103
14104 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
14105 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
14106
14107 old_parent = SetParent(child, GetDesktopWindow());
14108 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
14109
14110 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
14111 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
14112
14113 old_focus = SetFocus(parent);
14114 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14115 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
14116 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14117 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14118
14119 flush_events();
14120 flush_sequence();
14121
14122 SetLastError(0xdeadbeef);
14123 old_focus = SetFocus(child);
14124 todo_wine
14125 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
14126 broken(GetLastError() == 0) /* XP */ ||
14127 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
14128 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14129 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
14130 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14131 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14132 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14133
14134 SetLastError(0xdeadbeef);
14135 old_active = SetActiveWindow(child);
14136 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
14137 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14138 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
14139 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
14140 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14141 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14142
14143 log_all_parent_messages--;
14144
14145 DestroyWindow(child);
14146 DestroyWindow(parent);
14147
14148 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
14149 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
14150 ret = WaitForSingleObject(hthread, INFINITE);
14151 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
14152 CloseHandle(hthread);
14153 }
14154
14155 static const struct message WmSetLayeredStyle[] = {
14156 { WM_STYLECHANGING, sent },
14157 { WM_STYLECHANGED, sent },
14158 { WM_GETTEXT, sent|defwinproc|optional },
14159 { 0 }
14160 };
14161
14162 static const struct message WmSetLayeredStyle2[] = {
14163 { WM_STYLECHANGING, sent },
14164 { WM_STYLECHANGED, sent },
14165 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14166 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
14167 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14168 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
14169 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
14170 { 0 }
14171 };
14172
14173 struct layered_window_info
14174 {
14175 HWND hwnd;
14176 HDC hdc;
14177 SIZE size;
14178 HANDLE event;
14179 BOOL ret;
14180 };
14181
14182 static DWORD CALLBACK update_layered_proc( void *param )
14183 {
14184 struct layered_window_info *info = param;
14185 POINT src = { 0, 0 };
14186
14187 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
14188 info->hdc, &src, 0, NULL, ULW_OPAQUE );
14189 ok( info->ret, "failed\n");
14190 SetEvent( info->event );
14191 return 0;
14192 }
14193
14194 static void test_layered_window(void)
14195 {
14196 HWND hwnd;
14197 HDC hdc;
14198 HBITMAP bmp;
14199 BOOL ret;
14200 SIZE size;
14201 POINT pos, src;
14202 RECT rect, client;
14203 HANDLE thread;
14204 DWORD tid;
14205 struct layered_window_info info;
14206
14207 if (!pUpdateLayeredWindow)
14208 {
14209 win_skip( "UpdateLayeredWindow not supported\n" );
14210 return;
14211 }
14212
14213 hdc = CreateCompatibleDC( 0 );
14214 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
14215 SelectObject( hdc, bmp );
14216
14217 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
14218 100, 100, 300, 300, 0, 0, 0, NULL);
14219 ok( hwnd != 0, "failed to create window\n" );
14220 ShowWindow( hwnd, SW_SHOWNORMAL );
14221 UpdateWindow( hwnd );
14222 flush_events();
14223 flush_sequence();
14224
14225 GetWindowRect( hwnd, &rect );
14226 GetClientRect( hwnd, &client );
14227 ok( client.right < rect.right - rect.left, "wrong client area\n" );
14228 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
14229
14230 src.x = src.y = 0;
14231 pos.x = pos.y = 300;
14232 size.cx = size.cy = 250;
14233 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14234 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14235 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
14236 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
14237 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
14238
14239 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14240 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14241 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14242 GetWindowRect( hwnd, &rect );
14243 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
14244 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14245 GetClientRect( hwnd, &rect );
14246 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
14247 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14248
14249 size.cx = 150;
14250 pos.y = 200;
14251 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14252 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14253 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14254 GetWindowRect( hwnd, &rect );
14255 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
14256 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14257 GetClientRect( hwnd, &rect );
14258 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
14259 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14260
14261 SetWindowLongA( hwnd, GWL_STYLE,
14262 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
14263 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
14264
14265 size.cx = 200;
14266 pos.x = 200;
14267 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14268 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14269 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14270 GetWindowRect( hwnd, &rect );
14271 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
14272 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14273 GetClientRect( hwnd, &rect );
14274 ok( (rect.right == 200 && rect.bottom == 250) ||
14275 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
14276 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14277
14278 size.cx = 0;
14279 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14280 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14281 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(ERROR_MR_MID_NOT_FOUND) /* win7 */,
14282 "wrong error %u\n", GetLastError() );
14283 size.cx = 1;
14284 size.cy = -1;
14285 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14286 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14287 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
14288
14289 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
14290 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
14291 GetWindowRect( hwnd, &rect );
14292 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
14293 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14294 GetClientRect( hwnd, &rect );
14295 ok( (rect.right == 200 && rect.bottom == 250) ||
14296 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
14297 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14298
14299 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
14300 info.hwnd = hwnd;
14301 info.hdc = hdc;
14302 info.size.cx = 250;
14303 info.size.cy = 300;
14304 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
14305 info.ret = FALSE;
14306 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
14307 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
14308 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
14309 WaitForSingleObject( thread, 1000 );
14310 CloseHandle( thread );
14311 GetWindowRect( hwnd, &rect );
14312 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
14313 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14314 GetClientRect( hwnd, &rect );
14315 ok( (rect.right == 250 && rect.bottom == 300) ||
14316 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
14317 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14318
14319 DestroyWindow( hwnd );
14320 DeleteDC( hdc );
14321 DeleteObject( bmp );
14322 }
14323
14324 static HMENU hpopupmenu;
14325
14326 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14327 {
14328 if (ignore_message( message )) return 0;
14329
14330 switch (message) {
14331 case WM_ENTERIDLE:
14332 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
14333 EndMenu();
14334 break;
14335 case WM_INITMENU:
14336 case WM_INITMENUPOPUP:
14337 case WM_UNINITMENUPOPUP:
14338 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
14339 break;
14340 }
14341
14342 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
14343 }
14344
14345 static void test_TrackPopupMenu(void)
14346 {
14347 HWND hwnd;
14348 BOOL ret;
14349
14350 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
14351 0, 0, 1, 1, 0,
14352 NULL, NULL, 0);
14353 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
14354
14355 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
14356
14357 hpopupmenu = CreatePopupMenu();
14358 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
14359
14360 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
14361 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
14362
14363 flush_events();
14364 flush_sequence();
14365 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
14366 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
14367 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
14368
14369 DestroyMenu(hpopupmenu);
14370 DestroyWindow(hwnd);
14371 }
14372
14373 static void test_TrackPopupMenuEmpty(void)
14374 {
14375 HWND hwnd;
14376 BOOL ret;
14377
14378 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
14379 0, 0, 1, 1, 0,
14380 NULL, NULL, 0);
14381 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
14382
14383 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
14384
14385 hpopupmenu = CreatePopupMenu();
14386 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
14387
14388 flush_events();
14389 flush_sequence();
14390 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
14391 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
14392 todo_wine ok(ret == 0, "TrackPopupMenu succeeded\n");
14393
14394 DestroyMenu(hpopupmenu);
14395 DestroyWindow(hwnd);
14396 }
14397
14398 static void init_funcs(void)
14399 {
14400 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
14401
14402 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
14403 X(ActivateActCtx);
14404 X(CreateActCtxW);
14405 X(DeactivateActCtx);
14406 X(GetCurrentActCtx);
14407 X(ReleaseActCtx);
14408 #undef X
14409 }
14410
14411 START_TEST(msg)
14412 {
14413 char **test_argv;
14414 BOOL ret;
14415 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
14416 HMODULE hModuleImm32;
14417 BOOL (WINAPI *pImmDisableIME)(DWORD);
14418 int argc;
14419
14420 init_funcs();
14421
14422 argc = winetest_get_mainargs( &test_argv );
14423 if (argc >= 3)
14424 {
14425 unsigned int arg;
14426 /* Child process. */
14427 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
14428 do_wait_idle_child( arg );
14429 return;
14430 }
14431
14432 InitializeCriticalSection( &sequence_cs );
14433 init_procs();
14434
14435 hModuleImm32 = LoadLibraryA("imm32.dll");
14436 if (hModuleImm32) {
14437 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
14438 if (pImmDisableIME)
14439 pImmDisableIME(0);
14440 }
14441 pImmDisableIME = NULL;
14442 FreeLibrary(hModuleImm32);
14443
14444 if (!RegisterWindowClasses()) assert(0);
14445
14446 if (pSetWinEventHook)
14447 {
14448 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
14449 GetModuleHandleA(0), win_event_proc,
14450 0, GetCurrentThreadId(),
14451 WINEVENT_INCONTEXT);
14452 if (pIsWinEventHookInstalled && hEvent_hook)
14453 {
14454 UINT event;
14455 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
14456 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
14457 }
14458 }
14459 if (!hEvent_hook) win_skip( "no win event hook support\n" );
14460
14461 cbt_hook_thread_id = GetCurrentThreadId();
14462 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
14463 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
14464
14465 test_winevents();
14466
14467 /* Fix message sequences before removing 4 lines below */
14468 if (pUnhookWinEvent && hEvent_hook)
14469 {
14470 ret = pUnhookWinEvent(hEvent_hook);
14471 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14472 pUnhookWinEvent = 0;
14473 }
14474 hEvent_hook = 0;
14475 test_SetFocus();
14476 test_SetParent();
14477 test_PostMessage();
14478 test_ShowWindow();
14479 test_PeekMessage();
14480 test_PeekMessage2();
14481 test_WaitForInputIdle( test_argv[0] );
14482 test_scrollwindowex();
14483 test_messages();
14484 test_setwindowpos();
14485 test_showwindow();
14486 invisible_parent_tests();
14487 test_mdi_messages();
14488 test_button_messages();
14489 test_static_messages();
14490 test_listbox_messages();
14491 test_combobox_messages();
14492 test_wmime_keydown_message();
14493 test_paint_messages();
14494 test_interthread_messages();
14495 test_message_conversion();
14496 test_accelerators();
14497 test_timers();
14498 test_timers_no_wnd();
14499 if (hCBT_hook) test_set_hook();
14500 test_DestroyWindow();
14501 test_DispatchMessage();
14502 test_SendMessageTimeout();
14503 test_edit_messages();
14504 test_quit_message();
14505 test_SetActiveWindow();
14506
14507 if (!pTrackMouseEvent)
14508 win_skip("TrackMouseEvent is not available\n");
14509 else
14510 test_TrackMouseEvent();
14511
14512 test_SetWindowRgn();
14513 test_sys_menu();
14514 test_dialog_messages();
14515 test_EndDialog();
14516 test_nullCallback();
14517 test_dbcs_wm_char();
14518 test_unicode_wm_char();
14519 test_menu_messages();
14520 test_paintingloop();
14521 test_defwinproc();
14522 test_clipboard_viewers();
14523 test_keyflags();
14524 test_hotkey();
14525 test_layered_window();
14526 test_TrackPopupMenu();
14527 test_TrackPopupMenuEmpty();
14528 /* keep it the last test, under Windows it tends to break the tests
14529 * which rely on active/foreground windows being correct.
14530 */
14531 test_SetForegroundWindow();
14532
14533 UnhookWindowsHookEx(hCBT_hook);
14534 if (pUnhookWinEvent && hEvent_hook)
14535 {
14536 ret = pUnhookWinEvent(hEvent_hook);
14537 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14538 SetLastError(0xdeadbeef);
14539 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
14540 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
14541 GetLastError() == 0xdeadbeef, /* Win9x */
14542 "unexpected error %d\n", GetLastError());
14543 }
14544 DeleteCriticalSection( &sequence_cs );
14545 }