[USER32_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 WmTrackPopupMenuCapture[] = {
1751 { HCBT_CREATEWND, hook },
1752 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1753 { WM_CAPTURECHANGED, sent },
1754 { WM_INITMENU, sent|lparam, 0, 0 },
1755 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1756 { 0x0093, sent|optional },
1757 { 0x0094, sent|optional },
1758 { 0x0094, sent|optional },
1759 { WM_ENTERIDLE, sent|wparam, 2 },
1760 { WM_CAPTURECHANGED, sent },
1761 { HCBT_DESTROYWND, hook },
1762 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1763 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1764 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1765 { 0 }
1766 };
1767
1768 static const struct message WmTrackPopupMenuEmpty[] = {
1769 { HCBT_CREATEWND, hook },
1770 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1771 { WM_INITMENU, sent|lparam, 0, 0 },
1772 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1773 { 0x0093, sent|optional },
1774 { 0x0094, sent|optional },
1775 { 0x0094, sent|optional },
1776 { WM_CAPTURECHANGED, sent },
1777 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1778 { HCBT_DESTROYWND, hook },
1779 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1780 { 0 }
1781 };
1782
1783 static const struct message WmTrackPopupMenuAbort[] = {
1784 { HCBT_CREATEWND, hook },
1785 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1786 { WM_INITMENU, sent|lparam, 0, 0 },
1787 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1788 { 0x0093, sent|optional },
1789 { 0x0094, sent|optional },
1790 { 0x0094, sent|optional },
1791 { WM_CAPTURECHANGED, sent },
1792 { HCBT_DESTROYWND, hook },
1793 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1794 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1795 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1796 { 0 }
1797 };
1798
1799 static BOOL after_end_dialog, test_def_id, paint_loop_done;
1800 static int sequence_cnt, sequence_size;
1801 static struct recvd_message* sequence;
1802 static int log_all_parent_messages;
1803 static CRITICAL_SECTION sequence_cs;
1804
1805 /* user32 functions */
1806 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1807 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1808 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1809 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1810 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1811 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1812 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1813 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
1814 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
1815 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
1816 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
1817 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
1818 /* kernel32 functions */
1819 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1820
1821 static void init_procs(void)
1822 {
1823 HMODULE user32 = GetModuleHandleA("user32.dll");
1824 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1825
1826 #define GET_PROC(dll, func) \
1827 p ## func = (void*)GetProcAddress(dll, #func); \
1828 if(!p ## func) { \
1829 trace("GetProcAddress(%s) failed\n", #func); \
1830 }
1831
1832 GET_PROC(user32, GetAncestor)
1833 GET_PROC(user32, GetMenuInfo)
1834 GET_PROC(user32, NotifyWinEvent)
1835 GET_PROC(user32, SetMenuInfo)
1836 GET_PROC(user32, SetWinEventHook)
1837 GET_PROC(user32, TrackMouseEvent)
1838 GET_PROC(user32, UnhookWinEvent)
1839 GET_PROC(user32, GetMonitorInfoA)
1840 GET_PROC(user32, MonitorFromPoint)
1841 GET_PROC(user32, UpdateLayeredWindow)
1842 GET_PROC(user32, SetSystemTimer)
1843 GET_PROC(user32, KillSystemTimer)
1844
1845 GET_PROC(kernel32, GetCPInfoExA)
1846
1847 #undef GET_PROC
1848 }
1849
1850 static const char *get_winpos_flags(UINT flags)
1851 {
1852 static char buffer[300];
1853
1854 buffer[0] = 0;
1855 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1856 DUMP( SWP_SHOWWINDOW );
1857 DUMP( SWP_HIDEWINDOW );
1858 DUMP( SWP_NOACTIVATE );
1859 DUMP( SWP_FRAMECHANGED );
1860 DUMP( SWP_NOCOPYBITS );
1861 DUMP( SWP_NOOWNERZORDER );
1862 DUMP( SWP_NOSENDCHANGING );
1863 DUMP( SWP_DEFERERASE );
1864 DUMP( SWP_ASYNCWINDOWPOS );
1865 DUMP( SWP_NOZORDER );
1866 DUMP( SWP_NOREDRAW );
1867 DUMP( SWP_NOSIZE );
1868 DUMP( SWP_NOMOVE );
1869 DUMP( SWP_NOCLIENTSIZE );
1870 DUMP( SWP_NOCLIENTMOVE );
1871 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1872 return buffer + 1;
1873 #undef DUMP
1874 }
1875
1876 static BOOL ignore_message( UINT message )
1877 {
1878 /* these are always ignored */
1879 return (message >= 0xc000 ||
1880 message == WM_GETICON ||
1881 message == WM_GETOBJECT ||
1882 message == WM_TIMECHANGE ||
1883 message == WM_DISPLAYCHANGE ||
1884 message == WM_DEVICECHANGE ||
1885 message == WM_DWMNCRENDERINGCHANGED);
1886 }
1887
1888
1889 #define add_message(msg) add_message_(__LINE__,msg);
1890 static void add_message_(int line, const struct recvd_message *msg)
1891 {
1892 struct recvd_message *seq;
1893
1894 EnterCriticalSection( &sequence_cs );
1895 if (!sequence)
1896 {
1897 sequence_size = 10;
1898 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1899 }
1900 if (sequence_cnt == sequence_size)
1901 {
1902 sequence_size *= 2;
1903 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1904 }
1905 assert(sequence);
1906
1907 seq = &sequence[sequence_cnt++];
1908 seq->hwnd = msg->hwnd;
1909 seq->message = msg->message;
1910 seq->flags = msg->flags;
1911 seq->wParam = msg->wParam;
1912 seq->lParam = msg->lParam;
1913 seq->line = line;
1914 seq->descr = msg->descr;
1915 seq->output[0] = 0;
1916 LeaveCriticalSection( &sequence_cs );
1917
1918 if (msg->descr)
1919 {
1920 if (msg->flags & hook)
1921 {
1922 static const char * const CBT_code_name[10] =
1923 {
1924 "HCBT_MOVESIZE",
1925 "HCBT_MINMAX",
1926 "HCBT_QS",
1927 "HCBT_CREATEWND",
1928 "HCBT_DESTROYWND",
1929 "HCBT_ACTIVATE",
1930 "HCBT_CLICKSKIPPED",
1931 "HCBT_KEYSKIPPED",
1932 "HCBT_SYSCOMMAND",
1933 "HCBT_SETFOCUS"
1934 };
1935 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1936
1937 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1938 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1939 }
1940 else if (msg->flags & winevent_hook)
1941 {
1942 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1943 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1944 }
1945 else
1946 {
1947 switch (msg->message)
1948 {
1949 case WM_WINDOWPOSCHANGING:
1950 case WM_WINDOWPOSCHANGED:
1951 {
1952 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1953
1954 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1955 msg->descr, msg->hwnd,
1956 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1957 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1958 winpos->x, winpos->y, winpos->cx, winpos->cy,
1959 get_winpos_flags(winpos->flags) );
1960
1961 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1962 * in the high word for internal purposes
1963 */
1964 seq->wParam = winpos->flags & 0xffff;
1965 /* We are not interested in the flags that don't match under XP and Win9x */
1966 seq->wParam &= ~SWP_NOZORDER;
1967 break;
1968 }
1969
1970 case WM_DRAWITEM:
1971 {
1972 DRAW_ITEM_STRUCT di;
1973 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1974
1975 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1976 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1977 dis->itemID, dis->itemAction, dis->itemState);
1978
1979 di.u.lp = 0;
1980 di.u.item.type = dis->CtlType;
1981 di.u.item.ctl_id = dis->CtlID;
1982 if (dis->CtlType == ODT_LISTBOX ||
1983 dis->CtlType == ODT_COMBOBOX ||
1984 dis->CtlType == ODT_MENU)
1985 di.u.item.item_id = dis->itemID;
1986 di.u.item.action = dis->itemAction;
1987 di.u.item.state = dis->itemState;
1988
1989 seq->lParam = di.u.lp;
1990 break;
1991 }
1992 default:
1993 if (msg->message >= 0xc000) return; /* ignore registered messages */
1994 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1995 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1996 }
1997 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1998 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1999 }
2000 }
2001 }
2002
2003 /* try to make sure pending X events have been processed before continuing */
2004 static void flush_events(void)
2005 {
2006 MSG msg;
2007 int diff = 200;
2008 int min_timeout = 100;
2009 DWORD time = GetTickCount() + diff;
2010
2011 while (diff > 0)
2012 {
2013 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2014 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2015 diff = time - GetTickCount();
2016 }
2017 }
2018
2019 static void flush_sequence(void)
2020 {
2021 EnterCriticalSection( &sequence_cs );
2022 HeapFree(GetProcessHeap(), 0, sequence);
2023 sequence = 0;
2024 sequence_cnt = sequence_size = 0;
2025 LeaveCriticalSection( &sequence_cs );
2026 }
2027
2028 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2029 {
2030 const struct recvd_message *actual = sequence;
2031 unsigned int count = 0;
2032
2033 trace_(file, line)("Failed sequence %s:\n", context );
2034 while (expected->message && actual->message)
2035 {
2036 if (actual->output[0])
2037 {
2038 if (expected->flags & hook)
2039 {
2040 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2041 count, expected->message, actual->output );
2042 }
2043 else if (expected->flags & winevent_hook)
2044 {
2045 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2046 count, expected->message, actual->output );
2047 }
2048 else if (expected->flags & kbd_hook)
2049 {
2050 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2051 count, expected->message, actual->output );
2052 }
2053 else
2054 {
2055 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2056 count, expected->message, actual->output );
2057 }
2058 }
2059
2060 if (expected->message == actual->message)
2061 {
2062 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2063 (expected->flags & optional))
2064 {
2065 /* don't match messages if their defwinproc status differs */
2066 expected++;
2067 }
2068 else
2069 {
2070 expected++;
2071 actual++;
2072 }
2073 }
2074 /* silently drop winevent messages if there is no support for them */
2075 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2076 expected++;
2077 else
2078 {
2079 expected++;
2080 actual++;
2081 }
2082 count++;
2083 }
2084
2085 /* optional trailing messages */
2086 while (expected->message && ((expected->flags & optional) ||
2087 ((expected->flags & winevent_hook) && !hEvent_hook)))
2088 {
2089 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2090 expected++;
2091 count++;
2092 }
2093
2094 if (expected->message)
2095 {
2096 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2097 return;
2098 }
2099
2100 while (actual->message && actual->output[0])
2101 {
2102 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2103 actual++;
2104 count++;
2105 }
2106 }
2107
2108 #define ok_sequence( exp, contx, todo) \
2109 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2110
2111
2112 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2113 const char *file, int line)
2114 {
2115 static const struct recvd_message end_of_sequence;
2116 const struct message *expected = expected_list;
2117 const struct recvd_message *actual;
2118 int failcount = 0, dump = 0;
2119 unsigned int count = 0;
2120
2121 add_message(&end_of_sequence);
2122
2123 actual = sequence;
2124
2125 while (expected->message && actual->message)
2126 {
2127 if (expected->message == actual->message &&
2128 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2129 {
2130 if (expected->flags & wparam)
2131 {
2132 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2133 {
2134 todo_wine {
2135 failcount ++;
2136 if (strcmp(winetest_platform, "wine")) dump++;
2137 ok_( file, line) (FALSE,
2138 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2139 context, count, expected->message, expected->wParam, actual->wParam);
2140 }
2141 }
2142 else
2143 {
2144 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2145 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2146 context, count, expected->message, expected->wParam, actual->wParam);
2147 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2148 }
2149
2150 }
2151 if (expected->flags & lparam)
2152 {
2153 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2154 {
2155 todo_wine {
2156 failcount ++;
2157 if (strcmp(winetest_platform, "wine")) dump++;
2158 ok_( file, line) (FALSE,
2159 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2160 context, count, expected->message, expected->lParam, actual->lParam);
2161 }
2162 }
2163 else
2164 {
2165 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2166 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2167 context, count, expected->message, expected->lParam, actual->lParam);
2168 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2169 }
2170 }
2171 if ((expected->flags & optional) &&
2172 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2173 {
2174 /* don't match optional messages if their defwinproc or parent status differs */
2175 expected++;
2176 count++;
2177 continue;
2178 }
2179 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2180 {
2181 todo_wine {
2182 failcount ++;
2183 if (strcmp(winetest_platform, "wine")) dump++;
2184 ok_( file, line) (FALSE,
2185 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2186 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2187 }
2188 }
2189 else
2190 {
2191 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2192 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2193 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2194 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2195 }
2196
2197 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2198 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2199 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2200 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2201
2202 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2203 "%s: %u: the msg 0x%04x should have been %s\n",
2204 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2205 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2206
2207 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2208 "%s: %u: the msg 0x%04x was expected in %s\n",
2209 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2210 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2211
2212 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2213 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2214 context, count, expected->message);
2215 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2216
2217 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2218 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2219 context, count, expected->message);
2220 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2221
2222 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2223 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2224 context, count, expected->message);
2225 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2226
2227 expected++;
2228 actual++;
2229 }
2230 /* silently drop hook messages if there is no support for them */
2231 else if ((expected->flags & optional) ||
2232 ((expected->flags & hook) && !hCBT_hook) ||
2233 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2234 ((expected->flags & kbd_hook) && !hKBD_hook))
2235 expected++;
2236 else if (todo)
2237 {
2238 failcount++;
2239 todo_wine {
2240 if (strcmp(winetest_platform, "wine")) dump++;
2241 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2242 context, count, expected->message, actual->message);
2243 }
2244 goto done;
2245 }
2246 else
2247 {
2248 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2249 context, count, expected->message, actual->message);
2250 dump++;
2251 expected++;
2252 actual++;
2253 }
2254 count++;
2255 }
2256
2257 /* skip all optional trailing messages */
2258 while (expected->message && ((expected->flags & optional) ||
2259 ((expected->flags & hook) && !hCBT_hook) ||
2260 ((expected->flags & winevent_hook) && !hEvent_hook)))
2261 expected++;
2262
2263 if (todo)
2264 {
2265 todo_wine {
2266 if (expected->message || actual->message) {
2267 failcount++;
2268 if (strcmp(winetest_platform, "wine")) dump++;
2269 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2270 context, count, expected->message, actual->message);
2271 }
2272 }
2273 }
2274 else
2275 {
2276 if (expected->message || actual->message)
2277 {
2278 dump++;
2279 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2280 context, count, expected->message, actual->message);
2281 }
2282 }
2283 if( todo && !failcount) /* succeeded yet marked todo */
2284 todo_wine {
2285 if (!strcmp(winetest_platform, "wine")) dump++;
2286 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2287 }
2288
2289 done:
2290 if (dump) dump_sequence(expected_list, context, file, line);
2291 flush_sequence();
2292 }
2293
2294 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2295
2296 /******************************** MDI test **********************************/
2297
2298 /* CreateWindow for MDI frame window, initially visible */
2299 static const struct message WmCreateMDIframeSeq[] = {
2300 { HCBT_CREATEWND, hook },
2301 { WM_GETMINMAXINFO, sent },
2302 { WM_NCCREATE, sent },
2303 { WM_NCCALCSIZE, sent|wparam, 0 },
2304 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2305 { WM_CREATE, sent },
2306 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2307 { WM_NOTIFYFORMAT, sent|optional },
2308 { WM_QUERYUISTATE, sent|optional },
2309 { WM_WINDOWPOSCHANGING, sent|optional },
2310 { WM_GETMINMAXINFO, sent|optional },
2311 { WM_NCCALCSIZE, sent|optional },
2312 { WM_WINDOWPOSCHANGED, sent|optional },
2313 { WM_SHOWWINDOW, sent|wparam, 1 },
2314 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2315 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2316 { HCBT_ACTIVATE, hook },
2317 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2318 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2319 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2320 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2321 { WM_NCACTIVATE, sent },
2322 { WM_GETTEXT, sent|defwinproc|optional },
2323 { WM_ACTIVATE, sent|wparam, 1 },
2324 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2325 { HCBT_SETFOCUS, hook },
2326 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2327 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2328 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2329 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2330 /* Win9x adds SWP_NOZORDER below */
2331 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2332 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2333 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2334 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2335 { WM_MOVE, sent },
2336 { 0 }
2337 };
2338 /* DestroyWindow for MDI frame window, initially visible */
2339 static const struct message WmDestroyMDIframeSeq[] = {
2340 { HCBT_DESTROYWND, hook },
2341 { 0x0090, sent|optional },
2342 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2343 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2344 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2345 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2346 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2347 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2348 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2349 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2350 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2351 { WM_DESTROY, sent },
2352 { WM_NCDESTROY, sent },
2353 { 0 }
2354 };
2355 /* CreateWindow for MDI client window, initially visible */
2356 static const struct message WmCreateMDIclientSeq[] = {
2357 { HCBT_CREATEWND, hook },
2358 { WM_NCCREATE, sent },
2359 { WM_NCCALCSIZE, sent|wparam, 0 },
2360 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2361 { WM_CREATE, sent },
2362 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2363 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2364 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2365 { WM_MOVE, sent },
2366 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2367 { WM_SHOWWINDOW, sent|wparam, 1 },
2368 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2369 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2370 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2371 { 0 }
2372 };
2373 /* ShowWindow(SW_SHOW) for MDI client window */
2374 static const struct message WmShowMDIclientSeq[] = {
2375 { WM_SHOWWINDOW, sent|wparam, 1 },
2376 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2377 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2378 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2379 { 0 }
2380 };
2381 /* ShowWindow(SW_HIDE) for MDI client window */
2382 static const struct message WmHideMDIclientSeq[] = {
2383 { WM_SHOWWINDOW, sent|wparam, 0 },
2384 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2385 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2386 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2387 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2388 { 0 }
2389 };
2390 /* DestroyWindow for MDI client window, initially visible */
2391 static const struct message WmDestroyMDIclientSeq[] = {
2392 { HCBT_DESTROYWND, hook },
2393 { 0x0090, sent|optional },
2394 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2395 { WM_SHOWWINDOW, sent|wparam, 0 },
2396 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2397 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2398 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2399 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2400 { WM_DESTROY, sent },
2401 { WM_NCDESTROY, sent },
2402 { 0 }
2403 };
2404 /* CreateWindow for MDI child window, initially visible */
2405 static const struct message WmCreateMDIchildVisibleSeq[] = {
2406 { HCBT_CREATEWND, hook },
2407 { WM_NCCREATE, sent },
2408 { WM_NCCALCSIZE, sent|wparam, 0 },
2409 { WM_CREATE, sent },
2410 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2411 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2412 { WM_MOVE, sent },
2413 /* Win2k sends wparam set to
2414 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2415 * while Win9x doesn't bother to set child window id according to
2416 * CLIENTCREATESTRUCT.idFirstChild
2417 */
2418 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2419 { WM_SHOWWINDOW, sent|wparam, 1 },
2420 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2421 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2422 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2423 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2424 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2425 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2426 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2427
2428 /* Win9x: message sequence terminates here. */
2429
2430 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2431 { HCBT_SETFOCUS, hook }, /* in MDI client */
2432 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2433 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2434 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2435 { WM_SETFOCUS, sent }, /* in MDI client */
2436 { HCBT_SETFOCUS, hook },
2437 { WM_KILLFOCUS, sent }, /* in MDI client */
2438 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2439 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2440 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2441 { WM_SETFOCUS, sent|defwinproc },
2442 { WM_MDIACTIVATE, sent|defwinproc },
2443 { 0 }
2444 };
2445 /* CreateWindow for MDI child window with invisible parent */
2446 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2447 { HCBT_CREATEWND, hook },
2448 { WM_GETMINMAXINFO, sent },
2449 { WM_NCCREATE, sent },
2450 { WM_NCCALCSIZE, sent|wparam, 0 },
2451 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2452 { WM_CREATE, sent },
2453 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2454 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2455 { WM_MOVE, sent },
2456 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2457 { WM_SHOWWINDOW, sent|wparam, 1 },
2458 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2459 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2460 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2461 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2462
2463 /* Win9x: message sequence terminates here. */
2464
2465 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2466 { HCBT_SETFOCUS, hook }, /* in MDI client */
2467 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2468 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2469 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2470 { WM_SETFOCUS, sent }, /* in MDI client */
2471 { HCBT_SETFOCUS, hook },
2472 { WM_KILLFOCUS, sent }, /* in MDI client */
2473 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2474 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2475 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2476 { WM_SETFOCUS, sent|defwinproc },
2477 { WM_MDIACTIVATE, sent|defwinproc },
2478 { 0 }
2479 };
2480 /* DestroyWindow for MDI child window, initially visible */
2481 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2482 { HCBT_DESTROYWND, hook },
2483 /* Win2k sends wparam set to
2484 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2485 * while Win9x doesn't bother to set child window id according to
2486 * CLIENTCREATESTRUCT.idFirstChild
2487 */
2488 { 0x0090, sent|optional },
2489 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2490 { WM_SHOWWINDOW, sent|wparam, 0 },
2491 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2492 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2493 { WM_ERASEBKGND, sent|parent|optional },
2494 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2495
2496 /* { WM_DESTROY, sent }
2497 * Win9x: message sequence terminates here.
2498 */
2499
2500 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2501 { WM_KILLFOCUS, sent },
2502 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2503 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2504 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2505 { WM_SETFOCUS, sent }, /* in MDI client */
2506
2507 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2508 { WM_KILLFOCUS, sent }, /* in MDI client */
2509 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2510 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2511 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2512 { WM_SETFOCUS, sent }, /* in MDI client */
2513
2514 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2515
2516 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2517 { WM_KILLFOCUS, sent },
2518 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2519 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2520 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2521 { WM_SETFOCUS, sent }, /* in MDI client */
2522
2523 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2524 { WM_KILLFOCUS, sent }, /* in MDI client */
2525 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2526 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2527 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2528 { WM_SETFOCUS, sent }, /* in MDI client */
2529
2530 { WM_DESTROY, sent },
2531
2532 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2533 { WM_KILLFOCUS, sent },
2534 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2535 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2536 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2537 { WM_SETFOCUS, sent }, /* in MDI client */
2538
2539 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2540 { WM_KILLFOCUS, sent }, /* in MDI client */
2541 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2542 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2543 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2544 { WM_SETFOCUS, sent }, /* in MDI client */
2545
2546 { WM_NCDESTROY, sent },
2547 { 0 }
2548 };
2549 /* CreateWindow for MDI child window, initially invisible */
2550 static const struct message WmCreateMDIchildInvisibleSeq[] = {
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 /* Win2k sends wparam set to
2559 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2560 * while Win9x doesn't bother to set child window id according to
2561 * CLIENTCREATESTRUCT.idFirstChild
2562 */
2563 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2564 { 0 }
2565 };
2566 /* DestroyWindow for MDI child window, initially invisible */
2567 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2568 { HCBT_DESTROYWND, hook },
2569 /* Win2k sends wparam set to
2570 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2571 * while Win9x doesn't bother to set child window id according to
2572 * CLIENTCREATESTRUCT.idFirstChild
2573 */
2574 { 0x0090, sent|optional },
2575 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2576 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2577 { WM_DESTROY, sent },
2578 { WM_NCDESTROY, sent },
2579 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2580 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2581 { 0 }
2582 };
2583 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2584 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2585 { HCBT_CREATEWND, hook },
2586 { WM_NCCREATE, sent },
2587 { WM_NCCALCSIZE, sent|wparam, 0 },
2588 { WM_CREATE, sent },
2589 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2590 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2591 { WM_MOVE, sent },
2592 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2593 { WM_GETMINMAXINFO, sent },
2594 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2595 { WM_NCCALCSIZE, sent|wparam, 1 },
2596 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2597 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2598 /* in MDI frame */
2599 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2600 { WM_NCCALCSIZE, sent|wparam, 1 },
2601 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2602 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2603 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2604 /* Win2k sends wparam set to
2605 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2606 * while Win9x doesn't bother to set child window id according to
2607 * CLIENTCREATESTRUCT.idFirstChild
2608 */
2609 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2610 { WM_SHOWWINDOW, sent|wparam, 1 },
2611 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2612 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2613 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2614 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2615 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2616 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2617 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2618
2619 /* Win9x: message sequence terminates here. */
2620
2621 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2622 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2623 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2624 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2625 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2626 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2627 { HCBT_SETFOCUS, hook|optional },
2628 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2629 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2630 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2631 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2632 { WM_SETFOCUS, sent|defwinproc|optional },
2633 { WM_MDIACTIVATE, sent|defwinproc|optional },
2634 /* in MDI frame */
2635 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2636 { WM_NCCALCSIZE, sent|wparam, 1 },
2637 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2638 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2639 { 0 }
2640 };
2641 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2642 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2643 /* restore the 1st MDI child */
2644 { WM_SETREDRAW, sent|wparam, 0 },
2645 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2646 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2647 { WM_NCCALCSIZE, sent|wparam, 1 },
2648 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2649 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2650 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2651 /* in MDI frame */
2652 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2653 { WM_NCCALCSIZE, sent|wparam, 1 },
2654 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2655 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2656 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2657 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2658 /* create the 2nd MDI child */
2659 { HCBT_CREATEWND, hook },
2660 { WM_NCCREATE, sent },
2661 { WM_NCCALCSIZE, sent|wparam, 0 },
2662 { WM_CREATE, sent },
2663 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2664 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2665 { WM_MOVE, sent },
2666 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2667 { WM_GETMINMAXINFO, sent },
2668 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2669 { WM_NCCALCSIZE, sent|wparam, 1 },
2670 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2671 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2672 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2673 /* in MDI frame */
2674 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2675 { WM_NCCALCSIZE, sent|wparam, 1 },
2676 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2677 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2678 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2679 /* Win2k sends wparam set to
2680 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2681 * while Win9x doesn't bother to set child window id according to
2682 * CLIENTCREATESTRUCT.idFirstChild
2683 */
2684 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2685 { WM_SHOWWINDOW, sent|wparam, 1 },
2686 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2687 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2688 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2689 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2690 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2691 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2692
2693 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2694 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2695
2696 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2697
2698 /* Win9x: message sequence terminates here. */
2699
2700 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2701 { HCBT_SETFOCUS, hook },
2702 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2703 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2704 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2705 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2706 { WM_SETFOCUS, sent }, /* in MDI client */
2707 { HCBT_SETFOCUS, hook },
2708 { WM_KILLFOCUS, sent }, /* in MDI client */
2709 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2710 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2711 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2712 { WM_SETFOCUS, sent|defwinproc },
2713
2714 { WM_MDIACTIVATE, sent|defwinproc },
2715 /* in MDI frame */
2716 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2717 { WM_NCCALCSIZE, sent|wparam, 1 },
2718 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2719 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2720 { 0 }
2721 };
2722 /* WM_MDICREATE MDI child window, initially visible and maximized */
2723 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2724 { WM_MDICREATE, sent },
2725 { HCBT_CREATEWND, hook },
2726 { WM_NCCREATE, sent },
2727 { WM_NCCALCSIZE, sent|wparam, 0 },
2728 { WM_CREATE, sent },
2729 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2730 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2731 { WM_MOVE, sent },
2732 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2733 { WM_GETMINMAXINFO, sent },
2734 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2735 { WM_NCCALCSIZE, sent|wparam, 1 },
2736 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2737 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2738
2739 /* in MDI frame */
2740 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2741 { WM_NCCALCSIZE, sent|wparam, 1 },
2742 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2743 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2744 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2745
2746 /* Win2k sends wparam set to
2747 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2748 * while Win9x doesn't bother to set child window id according to
2749 * CLIENTCREATESTRUCT.idFirstChild
2750 */
2751 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2752 { WM_SHOWWINDOW, sent|wparam, 1 },
2753 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2754
2755 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2756
2757 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2758 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2759 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2760
2761 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2762 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2763
2764 /* Win9x: message sequence terminates here. */
2765
2766 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2767 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2768 { HCBT_SETFOCUS, hook }, /* in MDI client */
2769 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2770 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2771 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2772 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2773 { HCBT_SETFOCUS, hook|optional },
2774 { WM_KILLFOCUS, sent }, /* in MDI client */
2775 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2776 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2777 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2778 { WM_SETFOCUS, sent|defwinproc },
2779
2780 { WM_MDIACTIVATE, sent|defwinproc },
2781
2782 /* in MDI child */
2783 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2784 { WM_NCCALCSIZE, sent|wparam, 1 },
2785 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2786 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2787
2788 /* in MDI frame */
2789 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2790 { WM_NCCALCSIZE, sent|wparam, 1 },
2791 { 0x0093, sent|defwinproc|optional },
2792 { 0x0093, sent|defwinproc|optional },
2793 { 0x0093, sent|defwinproc|optional },
2794 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2795 { WM_MOVE, sent|defwinproc },
2796 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2797
2798 /* in MDI client */
2799 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2800 { WM_NCCALCSIZE, sent|wparam, 1 },
2801 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2802 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2803
2804 /* in MDI child */
2805 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2806 { WM_NCCALCSIZE, sent|wparam, 1 },
2807 { 0x0093, sent|optional },
2808 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2809 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2810
2811 { 0x0093, sent|optional },
2812 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2813 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2814 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2815 { 0x0093, sent|defwinproc|optional },
2816 { 0x0093, sent|defwinproc|optional },
2817 { 0x0093, sent|defwinproc|optional },
2818 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2819 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2820
2821 { 0 }
2822 };
2823 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2824 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2825 { HCBT_CREATEWND, hook },
2826 { WM_GETMINMAXINFO, sent },
2827 { WM_NCCREATE, sent },
2828 { WM_NCCALCSIZE, sent|wparam, 0 },
2829 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2830 { WM_CREATE, sent },
2831 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2832 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2833 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2834 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2835 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2836 { WM_MOVE, sent },
2837 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2838 { WM_GETMINMAXINFO, sent },
2839 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2840 { WM_GETMINMAXINFO, sent|defwinproc },
2841 { WM_NCCALCSIZE, sent|wparam, 1 },
2842 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
2843 { WM_MOVE, sent|defwinproc },
2844 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2845 /* in MDI frame */
2846 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2847 { WM_NCCALCSIZE, sent|wparam, 1 },
2848 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2849 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2850 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2851 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2852 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2853 /* Win2k sends wparam set to
2854 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2855 * while Win9x doesn't bother to set child window id according to
2856 * CLIENTCREATESTRUCT.idFirstChild
2857 */
2858 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2859 { 0 }
2860 };
2861 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2862 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2863 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2864 { HCBT_SYSCOMMAND, hook },
2865 { WM_CLOSE, sent|defwinproc },
2866 { WM_MDIDESTROY, sent }, /* in MDI client */
2867
2868 /* bring the 1st MDI child to top */
2869 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2870 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2871
2872 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2873
2874 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2875 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2876 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2877
2878 /* maximize the 1st MDI child */
2879 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2880 { WM_GETMINMAXINFO, sent|defwinproc },
2881 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2882 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2883 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2884 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2885 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2886
2887 /* restore the 2nd MDI child */
2888 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2889 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2890 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2891 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2892
2893 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2894
2895 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2896 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2897
2898 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2899
2900 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2901 /* in MDI frame */
2902 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2903 { WM_NCCALCSIZE, sent|wparam, 1 },
2904 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2905 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2906 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2907
2908 /* bring the 1st MDI child to top */
2909 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2910 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2911 { HCBT_SETFOCUS, hook },
2912 { WM_KILLFOCUS, sent|defwinproc },
2913 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2914 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2915 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2916 { WM_SETFOCUS, sent }, /* in MDI client */
2917 { HCBT_SETFOCUS, hook },
2918 { WM_KILLFOCUS, sent }, /* in MDI client */
2919 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2920 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2921 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2922 { WM_SETFOCUS, sent|defwinproc },
2923 { WM_MDIACTIVATE, sent|defwinproc },
2924 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2925
2926 /* apparently ShowWindow(SW_SHOW) on an MDI client */
2927 { WM_SHOWWINDOW, sent|wparam, 1 },
2928 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2929 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2930 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2931 { WM_MDIREFRESHMENU, sent },
2932
2933 { HCBT_DESTROYWND, hook },
2934 /* Win2k sends wparam set to
2935 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2936 * while Win9x doesn't bother to set child window id according to
2937 * CLIENTCREATESTRUCT.idFirstChild
2938 */
2939 { 0x0090, sent|defwinproc|optional },
2940 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2941 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2942 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2943 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2944 { WM_ERASEBKGND, sent|parent|optional },
2945 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2946
2947 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2948 { WM_DESTROY, sent|defwinproc },
2949 { WM_NCDESTROY, sent|defwinproc },
2950 { 0 }
2951 };
2952 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2953 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2954 { WM_MDIDESTROY, sent }, /* in MDI client */
2955 { WM_SHOWWINDOW, sent|wparam, 0 },
2956 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2957 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2958 { WM_ERASEBKGND, sent|parent|optional },
2959 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2960
2961 { HCBT_SETFOCUS, hook },
2962 { WM_KILLFOCUS, sent },
2963 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2964 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2965 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2966 { WM_SETFOCUS, sent }, /* in MDI client */
2967 { HCBT_SETFOCUS, hook },
2968 { WM_KILLFOCUS, sent }, /* in MDI client */
2969 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2970 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2971 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2972 { WM_SETFOCUS, sent },
2973
2974 /* in MDI child */
2975 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2976 { WM_NCCALCSIZE, sent|wparam, 1 },
2977 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2978 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2979
2980 /* in MDI frame */
2981 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2982 { WM_NCCALCSIZE, sent|wparam, 1 },
2983 { 0x0093, sent|defwinproc|optional },
2984 { 0x0093, sent|defwinproc|optional },
2985 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2986 { WM_MOVE, sent|defwinproc },
2987 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2988
2989 /* in MDI client */
2990 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2991 { WM_NCCALCSIZE, sent|wparam, 1 },
2992 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2993 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2994
2995 /* in MDI child */
2996 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2997 { WM_NCCALCSIZE, sent|wparam, 1 },
2998 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2999 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3000
3001 /* in MDI child */
3002 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3003 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3004 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3005 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3006
3007 /* in MDI frame */
3008 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3009 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3010 { 0x0093, sent|defwinproc|optional },
3011 { 0x0093, sent|defwinproc|optional },
3012 { 0x0093, sent|defwinproc|optional },
3013 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3014 { WM_MOVE, sent|defwinproc },
3015 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3016
3017 /* in MDI client */
3018 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3019 { WM_NCCALCSIZE, sent|wparam, 1 },
3020 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3021 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3022
3023 /* in MDI child */
3024 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3025 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3026 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3027 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3028 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3029 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3030
3031 { 0x0093, sent|defwinproc|optional },
3032 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3033 { 0x0093, sent|defwinproc|optional },
3034 { 0x0093, sent|defwinproc|optional },
3035 { 0x0093, sent|defwinproc|optional },
3036 { 0x0093, sent|optional },
3037
3038 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3039 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3040 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3041 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3042 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3043
3044 /* in MDI frame */
3045 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3046 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3047 { 0x0093, sent|defwinproc|optional },
3048 { 0x0093, sent|defwinproc|optional },
3049 { 0x0093, sent|defwinproc|optional },
3050 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3051 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3052 { 0x0093, sent|optional },
3053
3054 { WM_NCACTIVATE, sent|wparam, 0 },
3055 { WM_MDIACTIVATE, sent },
3056
3057 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3058 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3059 { WM_NCCALCSIZE, sent|wparam, 1 },
3060
3061 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3062
3063 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3064 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3065 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3066
3067 /* in MDI child */
3068 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3069 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3070 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3071 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3072
3073 /* in MDI frame */
3074 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3075 { WM_NCCALCSIZE, sent|wparam, 1 },
3076 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3077 { WM_MOVE, sent|defwinproc },
3078 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3079
3080 /* in MDI client */
3081 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3082 { WM_NCCALCSIZE, sent|wparam, 1 },
3083 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3084 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3085 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3086 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3087 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3088 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3089 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3090
3091 { HCBT_SETFOCUS, hook },
3092 { WM_KILLFOCUS, sent },
3093 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3094 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3095 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3096 { WM_SETFOCUS, sent }, /* in MDI client */
3097
3098 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3099
3100 { HCBT_DESTROYWND, hook },
3101 /* Win2k sends wparam set to
3102 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3103 * while Win9x doesn't bother to set child window id according to
3104 * CLIENTCREATESTRUCT.idFirstChild
3105 */
3106 { 0x0090, sent|optional },
3107 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3108
3109 { WM_SHOWWINDOW, sent|wparam, 0 },
3110 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3111 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3112 { WM_ERASEBKGND, sent|parent|optional },
3113 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3114
3115 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3116 { WM_DESTROY, sent },
3117 { WM_NCDESTROY, sent },
3118 { 0 }
3119 };
3120 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3121 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3122 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3123 { WM_GETMINMAXINFO, sent },
3124 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3125 { WM_NCCALCSIZE, sent|wparam, 1 },
3126 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3127 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3128
3129 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3130 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3131 { HCBT_SETFOCUS, hook|optional },
3132 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3133 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3134 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3135 { HCBT_SETFOCUS, hook|optional },
3136 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3137 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3138 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3139 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3140 { WM_SETFOCUS, sent|optional|defwinproc },
3141 { WM_MDIACTIVATE, sent|optional|defwinproc },
3142 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3143 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3144 /* in MDI frame */
3145 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3146 { WM_NCCALCSIZE, sent|wparam, 1 },
3147 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3148 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3149 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3150 { 0 }
3151 };
3152 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3153 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3154 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3155 { WM_GETMINMAXINFO, sent },
3156 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3157 { WM_GETMINMAXINFO, sent|defwinproc },
3158 { WM_NCCALCSIZE, sent|wparam, 1 },
3159 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3160 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3161
3162 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3163 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3164 { HCBT_SETFOCUS, hook|optional },
3165 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3166 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3167 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3168 { HCBT_SETFOCUS, hook|optional },
3169 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3170 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3171 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3172 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3173 { WM_SETFOCUS, sent|defwinproc|optional },
3174 { WM_MDIACTIVATE, sent|defwinproc|optional },
3175 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3176 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3177 { 0 }
3178 };
3179 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3180 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3181 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3182 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3183 { WM_GETMINMAXINFO, sent },
3184 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3185 { WM_GETMINMAXINFO, sent|defwinproc },
3186 { WM_NCCALCSIZE, sent|wparam, 1 },
3187 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3188 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3189 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3190 { WM_MOVE, sent|defwinproc },
3191 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3192
3193 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3194 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3195 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
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 client XP */
3199 /* in MDI frame */
3200 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3201 { WM_NCCALCSIZE, sent|wparam, 1 },
3202 { 0x0093, sent|defwinproc|optional },
3203 { 0x0094, sent|defwinproc|optional },
3204 { 0x0094, sent|defwinproc|optional },
3205 { 0x0094, sent|defwinproc|optional },
3206 { 0x0094, sent|defwinproc|optional },
3207 { 0x0093, sent|defwinproc|optional },
3208 { 0x0093, sent|defwinproc|optional },
3209 { 0x0091, sent|defwinproc|optional },
3210 { 0x0092, sent|defwinproc|optional },
3211 { 0x0092, sent|defwinproc|optional },
3212 { 0x0092, sent|defwinproc|optional },
3213 { 0x0092, sent|defwinproc|optional },
3214 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3215 { WM_MOVE, sent|defwinproc },
3216 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3217 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3218 /* in MDI client */
3219 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3220 { WM_NCCALCSIZE, sent|wparam, 1 },
3221 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3222 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3223 /* in MDI child */
3224 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3225 { WM_GETMINMAXINFO, sent|defwinproc },
3226 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3227 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3228 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3229 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3230 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3231 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3232 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3233 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3234 /* in MDI frame */
3235 { 0x0093, sent|optional },
3236 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3237 { 0x0093, sent|defwinproc|optional },
3238 { 0x0093, sent|defwinproc|optional },
3239 { 0x0093, sent|defwinproc|optional },
3240 { 0x0091, sent|defwinproc|optional },
3241 { 0x0092, sent|defwinproc|optional },
3242 { 0x0092, sent|defwinproc|optional },
3243 { 0x0092, sent|defwinproc|optional },
3244 { 0x0092, sent|defwinproc|optional },
3245 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3246 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3247 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3248 { 0 }
3249 };
3250 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3251 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3252 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3253 { WM_GETMINMAXINFO, sent },
3254 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3255 { WM_NCCALCSIZE, sent|wparam, 1 },
3256 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3257 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3258 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3259 /* in MDI frame */
3260 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3261 { WM_NCCALCSIZE, sent|wparam, 1 },
3262 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3263 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3264 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3265 { 0 }
3266 };
3267 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3268 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3269 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3270 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3271 { WM_NCCALCSIZE, sent|wparam, 1 },
3272 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3273 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3274 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3275 /* in MDI frame */
3276 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3277 { WM_NCCALCSIZE, sent|wparam, 1 },
3278 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3279 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3280 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3281 { 0 }
3282 };
3283 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3284 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3285 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3286 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3287 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3288 { WM_NCCALCSIZE, sent|wparam, 1 },
3289 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3290 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3291 { WM_MOVE, sent|defwinproc },
3292 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3293 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3294 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3295 { HCBT_SETFOCUS, hook },
3296 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3297 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3298 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3299 { WM_SETFOCUS, sent },
3300 { 0 }
3301 };
3302 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3303 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3304 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3305 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3306 { WM_NCCALCSIZE, sent|wparam, 1 },
3307 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3308 { WM_MOVE, sent|defwinproc },
3309 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3310 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3311 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3312 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3313 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3314 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3315 { 0 }
3316 };
3317 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3318 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3319 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3320 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3321 { WM_NCCALCSIZE, sent|wparam, 1 },
3322 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3323 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3324 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3325 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3326 /* in MDI frame */
3327 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3328 { WM_NCCALCSIZE, sent|wparam, 1 },
3329 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3330 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3331 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3332 { 0 }
3333 };
3334
3335 static HWND mdi_client;
3336 static WNDPROC old_mdi_client_proc;
3337
3338 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3339 {
3340 struct recvd_message msg;
3341
3342 /* do not log painting messages */
3343 if (message != WM_PAINT &&
3344 message != WM_NCPAINT &&
3345 message != WM_SYNCPAINT &&
3346 message != WM_ERASEBKGND &&
3347 message != WM_NCHITTEST &&
3348 message != WM_GETTEXT &&
3349 message != WM_MDIGETACTIVE &&
3350 !ignore_message( message ))
3351 {
3352 msg.hwnd = hwnd;
3353 msg.message = message;
3354 msg.flags = sent|wparam|lparam;
3355 msg.wParam = wParam;
3356 msg.lParam = lParam;
3357 msg.descr = "mdi client";
3358 add_message(&msg);
3359 }
3360
3361 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3362 }
3363
3364 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3365 {
3366 static LONG defwndproc_counter = 0;
3367 LRESULT ret;
3368 struct recvd_message msg;
3369
3370 /* do not log painting messages */
3371 if (message != WM_PAINT &&
3372 message != WM_NCPAINT &&
3373 message != WM_SYNCPAINT &&
3374 message != WM_ERASEBKGND &&
3375 message != WM_NCHITTEST &&
3376 message != WM_GETTEXT &&
3377 !ignore_message( message ))
3378 {
3379 switch (message)
3380 {
3381 case WM_MDIACTIVATE:
3382 {
3383 HWND active, client = GetParent(hwnd);
3384
3385 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3386
3387 if (hwnd == (HWND)lParam) /* if we are being activated */
3388 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3389 else
3390 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3391 break;
3392 }
3393 }
3394
3395 msg.hwnd = hwnd;
3396 msg.message = message;
3397 msg.flags = sent|wparam|lparam;
3398 if (defwndproc_counter) msg.flags |= defwinproc;
3399 msg.wParam = wParam;
3400 msg.lParam = lParam;
3401 msg.descr = "mdi child";
3402 add_message(&msg);
3403 }
3404
3405 defwndproc_counter++;
3406 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3407 defwndproc_counter--;
3408
3409 return ret;
3410 }
3411
3412 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3413 {
3414 static LONG defwndproc_counter = 0;
3415 LRESULT ret;
3416 struct recvd_message msg;
3417
3418 /* do not log painting messages */
3419 if (message != WM_PAINT &&
3420 message != WM_NCPAINT &&
3421 message != WM_SYNCPAINT &&
3422 message != WM_ERASEBKGND &&
3423 message != WM_NCHITTEST &&
3424 message != WM_GETTEXT &&
3425 !ignore_message( message ))
3426 {
3427 msg.hwnd = hwnd;
3428 msg.message = message;
3429 msg.flags = sent|wparam|lparam;
3430 if (defwndproc_counter) msg.flags |= defwinproc;
3431 msg.wParam = wParam;
3432 msg.lParam = lParam;
3433 msg.descr = "mdi frame";
3434 add_message(&msg);
3435 }
3436
3437 defwndproc_counter++;
3438 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3439 defwndproc_counter--;
3440
3441 return ret;
3442 }
3443
3444 static BOOL mdi_RegisterWindowClasses(void)
3445 {
3446 WNDCLASSA cls;
3447
3448 cls.style = 0;
3449 cls.lpfnWndProc = mdi_frame_wnd_proc;
3450 cls.cbClsExtra = 0;
3451 cls.cbWndExtra = 0;
3452 cls.hInstance = GetModuleHandleA(0);
3453 cls.hIcon = 0;
3454 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3455 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3456 cls.lpszMenuName = NULL;
3457 cls.lpszClassName = "MDI_frame_class";
3458 if (!RegisterClassA(&cls)) return FALSE;
3459
3460 cls.lpfnWndProc = mdi_child_wnd_proc;
3461 cls.lpszClassName = "MDI_child_class";
3462 if (!RegisterClassA(&cls)) return FALSE;
3463
3464 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3465 old_mdi_client_proc = cls.lpfnWndProc;
3466 cls.hInstance = GetModuleHandleA(0);
3467 cls.lpfnWndProc = mdi_client_hook_proc;
3468 cls.lpszClassName = "MDI_client_class";
3469 if (!RegisterClassA(&cls)) assert(0);
3470
3471 return TRUE;
3472 }
3473
3474 static void test_mdi_messages(void)
3475 {
3476 MDICREATESTRUCTA mdi_cs;
3477 CLIENTCREATESTRUCT client_cs;
3478 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3479 BOOL zoomed;
3480 RECT rc;
3481 HMENU hMenu = CreateMenu();
3482
3483 if (!mdi_RegisterWindowClasses()) assert(0);
3484
3485 flush_sequence();
3486
3487 trace("creating MDI frame window\n");
3488 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3489 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3490 WS_MAXIMIZEBOX | WS_VISIBLE,
3491 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3492 GetDesktopWindow(), hMenu,
3493 GetModuleHandleA(0), NULL);
3494 assert(mdi_frame);
3495 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3496
3497 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3498 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3499
3500 trace("creating MDI client window\n");
3501 GetClientRect(mdi_frame, &rc);
3502 client_cs.hWindowMenu = 0;
3503 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3504 mdi_client = CreateWindowExA(0, "MDI_client_class",
3505 NULL,
3506 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3507 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3508 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3509 assert(mdi_client);
3510 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3511
3512 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3513 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3514
3515 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3516 ok(!active_child, "wrong active MDI child %p\n", active_child);
3517 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3518
3519 SetFocus(0);
3520 flush_sequence();
3521
3522 trace("creating invisible MDI child window\n");
3523 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3524 WS_CHILD,
3525 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3526 mdi_client, 0, GetModuleHandleA(0), NULL);
3527 assert(mdi_child);
3528
3529 flush_sequence();
3530 ShowWindow(mdi_child, SW_SHOWNORMAL);
3531 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3532
3533 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3534 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3535
3536 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3537 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3538
3539 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3540 ok(!active_child, "wrong active MDI child %p\n", active_child);
3541 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3542
3543 ShowWindow(mdi_child, SW_HIDE);
3544 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3545 flush_sequence();
3546
3547 ShowWindow(mdi_child, SW_SHOW);
3548 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3549
3550 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3551 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3552
3553 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3554 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3555
3556 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3557 ok(!active_child, "wrong active MDI child %p\n", active_child);
3558 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3559
3560 DestroyWindow(mdi_child);
3561 flush_sequence();
3562
3563 trace("creating visible MDI child window\n");
3564 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3565 WS_CHILD | WS_VISIBLE,
3566 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3567 mdi_client, 0, GetModuleHandleA(0), NULL);
3568 assert(mdi_child);
3569 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3570
3571 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3572 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3573
3574 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3575 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3576
3577 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3578 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3579 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3580 flush_sequence();
3581
3582 DestroyWindow(mdi_child);
3583 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3584
3585 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3586 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3587
3588 /* Win2k: MDI client still returns a just destroyed child as active
3589 * Win9x: MDI client returns 0
3590 */
3591 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3592 ok(active_child == mdi_child || /* win2k */
3593 !active_child, /* win9x */
3594 "wrong active MDI child %p\n", active_child);
3595 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3596
3597 flush_sequence();
3598
3599 trace("creating invisible MDI child window\n");
3600 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3601 WS_CHILD,
3602 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3603 mdi_client, 0, GetModuleHandleA(0), NULL);
3604 assert(mdi_child2);
3605 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3606
3607 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3608 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3609
3610 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3611 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3612
3613 /* Win2k: MDI client still returns a just destroyed child as active
3614 * Win9x: MDI client returns mdi_child2
3615 */
3616 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3617 ok(active_child == mdi_child || /* win2k */
3618 active_child == mdi_child2, /* win9x */
3619 "wrong active MDI child %p\n", active_child);
3620 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3621 flush_sequence();
3622
3623 ShowWindow(mdi_child2, SW_MAXIMIZE);
3624 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3625
3626 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3627 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3628
3629 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3630 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3631 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3632 flush_sequence();
3633
3634 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3635 ok(GetFocus() == mdi_child2 || /* win2k */
3636 GetFocus() == 0, /* win9x */
3637 "wrong focus window %p\n", GetFocus());
3638
3639 SetFocus(0);
3640 flush_sequence();
3641
3642 ShowWindow(mdi_child2, SW_HIDE);
3643 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3644
3645 ShowWindow(mdi_child2, SW_RESTORE);
3646 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3647 flush_sequence();
3648
3649 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3650 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3651
3652 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3653 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3654 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3655 flush_sequence();
3656
3657 SetFocus(0);
3658 flush_sequence();
3659
3660 ShowWindow(mdi_child2, SW_HIDE);
3661 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3662
3663 ShowWindow(mdi_child2, SW_SHOW);
3664 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3665
3666 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3667 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3668
3669 ShowWindow(mdi_child2, SW_MAXIMIZE);
3670 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3671
3672 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3673 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3674
3675 ShowWindow(mdi_child2, SW_RESTORE);
3676 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3677
3678 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3679 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3680
3681 ShowWindow(mdi_child2, SW_MINIMIZE);
3682 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3683
3684 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3685 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3686
3687 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3688 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3689 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3690 flush_sequence();
3691
3692 ShowWindow(mdi_child2, SW_RESTORE);
3693 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3694
3695 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3696 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3697
3698 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3699 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3700 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3701 flush_sequence();
3702
3703 SetFocus(0);
3704 flush_sequence();
3705
3706 ShowWindow(mdi_child2, SW_HIDE);
3707 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3708
3709 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3710 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3711
3712 DestroyWindow(mdi_child2);
3713 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3714
3715 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3716 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3717
3718 /* test for maximized MDI children */
3719 trace("creating maximized visible MDI child window 1\n");
3720 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3721 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3722 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3723 mdi_client, 0, GetModuleHandleA(0), NULL);
3724 assert(mdi_child);
3725 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3726 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3727
3728 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3729 ok(GetFocus() == mdi_child || /* win2k */
3730 GetFocus() == 0, /* win9x */
3731 "wrong focus window %p\n", GetFocus());
3732
3733 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3734 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3735 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3736 flush_sequence();
3737
3738 trace("creating maximized visible MDI child window 2\n");
3739 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3740 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3741 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3742 mdi_client, 0, GetModuleHandleA(0), NULL);
3743 assert(mdi_child2);
3744 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3745 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3746 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3747
3748 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3749 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3750
3751 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3752 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3753 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3754 flush_sequence();
3755
3756 trace("destroying maximized visible MDI child window 2\n");
3757 DestroyWindow(mdi_child2);
3758 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3759
3760 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3761
3762 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3763 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3764
3765 /* Win2k: MDI client still returns a just destroyed child as active
3766 * Win9x: MDI client returns 0
3767 */
3768 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3769 ok(active_child == mdi_child2 || /* win2k */
3770 !active_child, /* win9x */
3771 "wrong active MDI child %p\n", active_child);
3772 flush_sequence();
3773
3774 ShowWindow(mdi_child, SW_MAXIMIZE);
3775 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3776 flush_sequence();
3777
3778 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3779 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3780
3781 trace("re-creating maximized visible MDI child window 2\n");
3782 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3783 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3784 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3785 mdi_client, 0, GetModuleHandleA(0), NULL);
3786 assert(mdi_child2);
3787 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3788 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3789 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3790
3791 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3792 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3793
3794 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3795 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3796 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3797 flush_sequence();
3798
3799 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3800 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3801 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3802
3803 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3804 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3805 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3806
3807 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3808 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3809 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3810 flush_sequence();
3811
3812 DestroyWindow(mdi_child);
3813 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3814
3815 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3816 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3817
3818 /* Win2k: MDI client still returns a just destroyed child as active
3819 * Win9x: MDI client returns 0
3820 */
3821 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3822 ok(active_child == mdi_child || /* win2k */
3823 !active_child, /* win9x */
3824 "wrong active MDI child %p\n", active_child);
3825 flush_sequence();
3826
3827 trace("creating maximized invisible MDI child window\n");
3828 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3829 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3830 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3831 mdi_client, 0, GetModuleHandleA(0), NULL);
3832 assert(mdi_child2);
3833 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3834 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3835 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3836 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3837
3838 /* Win2k: MDI client still returns a just destroyed child as active
3839 * Win9x: MDI client returns 0
3840 */
3841 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3842 ok(active_child == mdi_child || /* win2k */
3843 !active_child || active_child == mdi_child2, /* win9x */
3844 "wrong active MDI child %p\n", active_child);
3845 flush_sequence();
3846
3847 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3848 ShowWindow(mdi_child2, SW_MAXIMIZE);
3849 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3850 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3851 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3852 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3853
3854 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3855 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3856 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3857 flush_sequence();
3858
3859 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3860 flush_sequence();
3861
3862 /* end of test for maximized MDI children */
3863 SetFocus(0);
3864 flush_sequence();
3865 trace("creating maximized visible MDI child window 1(Switch test)\n");
3866 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3867 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3868 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3869 mdi_client, 0, GetModuleHandleA(0), NULL);
3870 assert(mdi_child);
3871 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3872 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3873
3874 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3875 ok(GetFocus() == mdi_child || /* win2k */
3876 GetFocus() == 0, /* win9x */
3877 "wrong focus window %p(Switch test)\n", GetFocus());
3878
3879 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3880 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3881 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3882 flush_sequence();
3883
3884 trace("creating maximized visible MDI child window 2(Switch test)\n");
3885 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3886 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3887 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3888 mdi_client, 0, GetModuleHandleA(0), NULL);
3889 assert(mdi_child2);
3890 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3891
3892 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3893 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3894
3895 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3896 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3897
3898 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3899 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3900 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3901 flush_sequence();
3902
3903 trace("Switch child window.\n");
3904 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3905 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3906 trace("end of test for switch maximized MDI children\n");
3907 flush_sequence();
3908
3909 /* Prepare for switching test of not maximized MDI children */
3910 ShowWindow( mdi_child, SW_NORMAL );
3911 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3912 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3913 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3914 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3915 flush_sequence();
3916
3917 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3918 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3919 trace("end of test for switch not maximized MDI children\n");
3920 flush_sequence();
3921
3922 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3923 flush_sequence();
3924
3925 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3926 flush_sequence();
3927
3928 SetFocus(0);
3929 flush_sequence();
3930 /* end of tests for switch maximized/not maximized MDI children */
3931
3932 mdi_cs.szClass = "MDI_child_Class";
3933 mdi_cs.szTitle = "MDI child";
3934 mdi_cs.hOwner = GetModuleHandleA(0);
3935 mdi_cs.x = 0;
3936 mdi_cs.y = 0;
3937 mdi_cs.cx = CW_USEDEFAULT;
3938 mdi_cs.cy = CW_USEDEFAULT;
3939 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3940 mdi_cs.lParam = 0;
3941 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3942 ok(mdi_child != 0, "MDI child creation failed\n");
3943 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3944
3945 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3946
3947 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3948 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3949
3950 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3951 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3952 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3953
3954 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3955 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3956 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3957 flush_sequence();
3958
3959 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3960 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3961
3962 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3963 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3964 ok(!active_child, "wrong active MDI child %p\n", active_child);
3965
3966 SetFocus(0);
3967 flush_sequence();
3968
3969 DestroyWindow(mdi_client);
3970 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3971
3972 /* test maximization of MDI child with invisible parent */
3973 client_cs.hWindowMenu = 0;
3974 mdi_client = CreateWindowA("MDI_client_class",
3975 NULL,
3976 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3977 0, 0, 660, 430,
3978 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3979 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3980
3981 ShowWindow(mdi_client, SW_HIDE);
3982 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3983
3984 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3985 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3986 0, 0, 650, 440,
3987 mdi_client, 0, GetModuleHandleA(0), NULL);
3988 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3989
3990 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3991 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3992 zoomed = IsZoomed(mdi_child);
3993 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3994
3995 ShowWindow(mdi_client, SW_SHOW);
3996 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3997
3998 DestroyWindow(mdi_child);
3999 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4000
4001 /* end of test for maximization of MDI child with invisible parent */
4002
4003 DestroyWindow(mdi_client);
4004 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4005
4006 DestroyWindow(mdi_frame);
4007 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4008 }
4009 /************************* End of MDI test **********************************/
4010
4011 static void test_WM_SETREDRAW(HWND hwnd)
4012 {
4013 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4014
4015 flush_events();
4016 flush_sequence();
4017
4018 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4019 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4020
4021 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4022 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4023
4024 flush_sequence();
4025 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4026 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4027
4028 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4029 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4030
4031 /* restore original WS_VISIBLE state */
4032 SetWindowLongA(hwnd, GWL_STYLE, style);
4033
4034 flush_events();
4035 flush_sequence();
4036 }
4037
4038 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4039 {
4040 struct recvd_message msg;
4041
4042 if (ignore_message( message )) return 0;
4043
4044 switch (message)
4045 {
4046 /* ignore */
4047 case WM_MOUSEMOVE:
4048 case WM_NCMOUSEMOVE:
4049 case WM_NCMOUSELEAVE:
4050 case WM_SETCURSOR:
4051 return 0;
4052 case WM_NCHITTEST:
4053 return HTCLIENT;
4054 }
4055
4056 msg.hwnd = hwnd;
4057 msg.message = message;
4058 msg.flags = sent|wparam|lparam;
4059 msg.wParam = wParam;
4060 msg.lParam = lParam;
4061 msg.descr = "dialog";
4062 add_message(&msg);
4063
4064 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4065 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4066 return 0;
4067 }
4068
4069 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4070 {
4071 DWORD style, exstyle;
4072 INT xmin, xmax;
4073 BOOL ret;
4074
4075 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4076 style = GetWindowLongA(hwnd, GWL_STYLE);
4077 /* do not be confused by WS_DLGFRAME set */
4078 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4079
4080 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4081 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4082
4083 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4084 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4085 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4086 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4087 else
4088 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4089
4090 style = GetWindowLongA(hwnd, GWL_STYLE);
4091 if (set) ok(style & set, "style %08x should be set\n", set);
4092 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4093
4094 /* a subsequent call should do nothing */
4095 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4096 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4097 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4098
4099 xmin = 0xdeadbeef;
4100 xmax = 0xdeadbeef;
4101 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4102 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4103 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4104 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4105 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4106 }
4107
4108 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4109 {
4110 DWORD style, exstyle;
4111 SCROLLINFO si;
4112 BOOL ret;
4113
4114 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4115 style = GetWindowLongA(hwnd, GWL_STYLE);
4116 /* do not be confused by WS_DLGFRAME set */
4117 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4118
4119 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4120 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4121
4122 si.cbSize = sizeof(si);
4123 si.fMask = SIF_RANGE;
4124 si.nMin = min;
4125 si.nMax = max;
4126 SetScrollInfo(hwnd, ctl, &si, TRUE);
4127 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4128 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4129 else
4130 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4131
4132 style = GetWindowLongA(hwnd, GWL_STYLE);
4133 if (set) ok(style & set, "style %08x should be set\n", set);
4134 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4135
4136 /* a subsequent call should do nothing */
4137 SetScrollInfo(hwnd, ctl, &si, TRUE);
4138 if (style & WS_HSCROLL)
4139 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4140 else if (style & WS_VSCROLL)
4141 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4142 else
4143 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4144
4145 si.fMask = SIF_PAGE;
4146 si.nPage = 5;
4147 SetScrollInfo(hwnd, ctl, &si, FALSE);
4148 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4149
4150 si.fMask = SIF_POS;
4151 si.nPos = max - 1;
4152 SetScrollInfo(hwnd, ctl, &si, FALSE);
4153 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4154
4155 si.fMask = SIF_RANGE;
4156 si.nMin = 0xdeadbeef;
4157 si.nMax = 0xdeadbeef;
4158 ret = GetScrollInfo(hwnd, ctl, &si);
4159 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4160 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4161 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4162 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4163 }
4164
4165 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4166 static void test_scroll_messages(HWND hwnd)
4167 {
4168 SCROLLINFO si;
4169 INT min, max;
4170 BOOL ret;
4171
4172 flush_events();
4173 flush_sequence();
4174
4175 min = 0xdeadbeef;
4176 max = 0xdeadbeef;
4177 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4178 ok( ret, "GetScrollRange error %d\n", GetLastError());
4179 if (sequence->message != WmGetScrollRangeSeq[0].message)
4180 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4181 /* values of min and max are undefined */
4182 flush_sequence();
4183
4184 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4185 ok( ret, "SetScrollRange error %d\n", GetLastError());
4186 if (sequence->message != WmSetScrollRangeSeq[0].message)
4187 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4188 flush_sequence();
4189
4190 min = 0xdeadbeef;
4191 max = 0xdeadbeef;
4192 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4193 ok( ret, "GetScrollRange error %d\n", GetLastError());
4194 if (sequence->message != WmGetScrollRangeSeq[0].message)
4195 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4196 /* values of min and max are undefined */
4197 flush_sequence();
4198
4199 si.cbSize = sizeof(si);
4200 si.fMask = SIF_RANGE;
4201 si.nMin = 20;
4202 si.nMax = 160;
4203 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4204 if (sequence->message != WmSetScrollRangeSeq[0].message)
4205 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4206 flush_sequence();
4207
4208 si.fMask = SIF_PAGE;
4209 si.nPage = 10;
4210 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4211 if (sequence->message != WmSetScrollRangeSeq[0].message)
4212 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4213 flush_sequence();
4214
4215 si.fMask = SIF_POS;
4216 si.nPos = 20;
4217 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4218 if (sequence->message != WmSetScrollRangeSeq[0].message)
4219 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4220 flush_sequence();
4221
4222 si.fMask = SIF_RANGE;
4223 si.nMin = 0xdeadbeef;
4224 si.nMax = 0xdeadbeef;
4225 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4226 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4227 if (sequence->message != WmGetScrollInfoSeq[0].message)
4228 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4229 /* values of min and max are undefined */
4230 flush_sequence();
4231
4232 /* set WS_HSCROLL */
4233 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4234 /* clear WS_HSCROLL */
4235 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4236
4237 /* set WS_HSCROLL */
4238 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4239 /* clear WS_HSCROLL */
4240 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4241
4242 /* set WS_VSCROLL */
4243 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4244 /* clear WS_VSCROLL */
4245 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4246
4247 /* set WS_VSCROLL */
4248 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4249 /* clear WS_VSCROLL */
4250 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4251 }
4252
4253 static void test_showwindow(void)
4254 {
4255 HWND hwnd, hchild;
4256 RECT rc;
4257
4258 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4259 100, 100, 200, 200, 0, 0, 0, NULL);
4260 ok (hwnd != 0, "Failed to create overlapped window\n");
4261 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4262 0, 0, 10, 10, hwnd, 0, 0, NULL);
4263 ok (hchild != 0, "Failed to create child\n");
4264 flush_sequence();
4265
4266 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4267 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4268 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4269 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4270
4271 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4272 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4273 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4274 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4275 /* back to invisible */
4276 ShowWindow(hchild, SW_HIDE);
4277 ShowWindow(hwnd, SW_HIDE);
4278 flush_sequence();
4279 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4280 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4281 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4282 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4283 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4284 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4285 flush_sequence();
4286 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4287 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4288 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4289 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4290 ShowWindow( hwnd, SW_SHOW);
4291 flush_sequence();
4292 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4293 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4294 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4295
4296 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4297 ShowWindow( hchild, SW_HIDE);
4298 flush_sequence();
4299 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4300 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4301 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4302
4303 SetCapture(hchild);
4304 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4305 DestroyWindow(hchild);
4306 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4307
4308 DestroyWindow(hwnd);
4309 flush_sequence();
4310
4311 /* Popup windows */
4312 /* Test 1:
4313 * 1. Create invisible maximized popup window.
4314 * 2. Move and resize it.
4315 * 3. 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 GetWindowRect(hwnd, &rc);
4325 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4326 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4327 "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4328 rc.left, rc.top, rc.right, rc.bottom);
4329 /* Reset window's size & position */
4330 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4331 ok(IsZoomed(hwnd), "window should be maximized\n");
4332 flush_sequence();
4333
4334 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4335 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4336 ok(IsZoomed(hwnd), "window should be maximized\n");
4337 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4338
4339 GetWindowRect(hwnd, &rc);
4340 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4341 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4342 "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4343 rc.left, rc.top, rc.right, rc.bottom);
4344 DestroyWindow(hwnd);
4345 flush_sequence();
4346
4347 /* Test 2:
4348 * 1. Create invisible maximized popup window.
4349 * 2. Show it maximized.
4350 */
4351 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4352 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4353 100, 100, 200, 200, 0, 0, 0, NULL);
4354 ok (hwnd != 0, "Failed to create popup window\n");
4355 ok(IsZoomed(hwnd), "window should be maximized\n");
4356 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4357
4358 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4359 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4360 ok(IsZoomed(hwnd), "window should be maximized\n");
4361 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4362 DestroyWindow(hwnd);
4363 flush_sequence();
4364
4365 /* Test 3:
4366 * 1. Create visible maximized popup window.
4367 */
4368 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4369 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4370 100, 100, 200, 200, 0, 0, 0, NULL);
4371 ok (hwnd != 0, "Failed to create popup window\n");
4372 ok(IsZoomed(hwnd), "window should be maximized\n");
4373 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4374 DestroyWindow(hwnd);
4375 flush_sequence();
4376
4377 /* Test 4:
4378 * 1. Create visible popup window.
4379 * 2. Maximize it.
4380 */
4381 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4382 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4383 100, 100, 200, 200, 0, 0, 0, NULL);
4384 ok (hwnd != 0, "Failed to create popup window\n");
4385 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4386 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4387
4388 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4389 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4390 ok(IsZoomed(hwnd), "window should be maximized\n");
4391 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4392 DestroyWindow(hwnd);
4393 flush_sequence();
4394 }
4395
4396 static void test_sys_menu(void)
4397 {
4398 HWND hwnd;
4399 HMENU hmenu;
4400 UINT state;
4401
4402 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4403 100, 100, 200, 200, 0, 0, 0, NULL);
4404 ok (hwnd != 0, "Failed to create overlapped window\n");
4405
4406 flush_sequence();
4407
4408 /* test existing window without CS_NOCLOSE style */
4409 hmenu = GetSystemMenu(hwnd, FALSE);
4410 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4411
4412 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4413 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4414 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4415
4416 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4417 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4418
4419 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4420 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4421 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4422
4423 EnableMenuItem(hmenu, SC_CLOSE, 0);
4424 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4425
4426 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4427 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4428 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4429
4430 /* test whether removing WS_SYSMENU destroys a system menu */
4431 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4432 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4433 flush_sequence();
4434 hmenu = GetSystemMenu(hwnd, FALSE);
4435 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4436
4437 DestroyWindow(hwnd);
4438
4439 /* test new window with CS_NOCLOSE style */
4440 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4441 100, 100, 200, 200, 0, 0, 0, NULL);
4442 ok (hwnd != 0, "Failed to create overlapped window\n");
4443
4444 hmenu = GetSystemMenu(hwnd, FALSE);
4445 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4446
4447 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4448 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4449
4450 DestroyWindow(hwnd);
4451
4452 /* test new window without WS_SYSMENU style */
4453 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4454 100, 100, 200, 200, 0, 0, 0, NULL);
4455 ok(hwnd != 0, "Failed to create overlapped window\n");
4456
4457 hmenu = GetSystemMenu(hwnd, FALSE);
4458 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4459
4460 DestroyWindow(hwnd);
4461 }
4462
4463 /* For shown WS_OVERLAPPEDWINDOW */
4464 static const struct message WmSetIcon_1[] = {
4465 { WM_SETICON, sent },
4466 { 0x00AE, sent|defwinproc|optional }, /* XP */
4467 { WM_GETTEXT, sent|defwinproc|optional },
4468 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4469 { 0 }
4470 };
4471
4472 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4473 static const struct message WmSetIcon_2[] = {
4474 { WM_SETICON, sent },
4475 { 0 }
4476 };
4477
4478 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4479 static const struct message WmInitEndSession[] = {
4480 { 0x003B, sent },
4481 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4482 { 0 }
4483 };
4484
4485 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4486 static const struct message WmInitEndSession_2[] = {
4487 { 0x003B, sent },
4488 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4489 { 0 }
4490 };
4491
4492 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4493 static const struct message WmInitEndSession_3[] = {
4494 { 0x003B, sent },
4495 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4496 { 0 }
4497 };
4498
4499 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4500 static const struct message WmInitEndSession_4[] = {
4501 { 0x003B, sent },
4502 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4503 { 0 }
4504 };
4505
4506 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4507 static const struct message WmInitEndSession_5[] = {
4508 { 0x003B, sent },
4509 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4510 { 0 }
4511 };
4512
4513 static const struct message WmOptionalPaint[] = {
4514 { WM_PAINT, sent|optional },
4515 { WM_NCPAINT, sent|beginpaint|optional },
4516 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4517 { WM_ERASEBKGND, sent|beginpaint|optional },
4518 { 0 }
4519 };
4520
4521 static const struct message WmZOrder[] = {
4522 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4523 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4524 { HCBT_ACTIVATE, hook },
4525 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4526 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4527 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4528 { WM_GETTEXT, sent|optional },
4529 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4530 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4531 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4532 { WM_GETTEXT, sent|defwinproc|optional },
4533 { WM_GETTEXT, sent|defwinproc|optional },
4534 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4535 { HCBT_SETFOCUS, hook },
4536 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4537 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4538 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4539 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4540 { WM_GETTEXT, sent|optional },
4541 { WM_NCCALCSIZE, sent|optional },
4542 { 0 }
4543 };
4544
4545 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4546 {
4547 DWORD ret;
4548 MSG msg;
4549
4550 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4551 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4552
4553 PostMessageA(hwnd, WM_USER, 0, 0);
4554
4555 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4556 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4557
4558 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4559 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4560
4561 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4562 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4563
4564 PostMessageA(hwnd, WM_USER, 0, 0);
4565
4566 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4567 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4568
4569 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4570 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4571
4572 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4573 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4574 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4575
4576 PostMessageA(hwnd, WM_USER, 0, 0);
4577
4578 /* new incoming message causes it to become signaled again */
4579 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4580 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4581
4582 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4583 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4584 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4585 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4586 }
4587
4588 /* test if we receive the right sequence of messages */
4589 static void test_messages(void)
4590 {
4591 HWND hwnd, hparent, hchild;
4592 HWND hchild2, hbutton;
4593 HMENU hmenu;
4594 MSG msg;
4595 LRESULT res;
4596 POINT pos;
4597
4598 flush_sequence();
4599
4600 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4601 100, 100, 200, 200, 0, 0, 0, NULL);
4602 ok (hwnd != 0, "Failed to create overlapped window\n");
4603 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4604
4605 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4606 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4607 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4608
4609 /* test WM_SETREDRAW on a not visible top level window */
4610 test_WM_SETREDRAW(hwnd);
4611
4612 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4613 flush_events();
4614 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4615 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4616
4617 ok(GetActiveWindow() == hwnd, "window should be active\n");
4618 ok(GetFocus() == hwnd, "window should have input focus\n");
4619 ShowWindow(hwnd, SW_HIDE);
4620 flush_events();
4621 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4622
4623 ShowWindow(hwnd, SW_SHOW);
4624 flush_events();
4625 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4626
4627 ShowWindow(hwnd, SW_HIDE);
4628 flush_events();
4629 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4630
4631 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4632 flush_events();
4633 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4634 flush_sequence();
4635
4636 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4637 {
4638 ShowWindow(hwnd, SW_RESTORE);
4639 flush_events();
4640 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4641 flush_sequence();
4642 }
4643
4644 ShowWindow(hwnd, SW_MINIMIZE);
4645 flush_events();
4646 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4647 flush_sequence();
4648
4649 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4650 {
4651 ShowWindow(hwnd, SW_RESTORE);
4652 flush_events();
4653 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4654 flush_sequence();
4655 }
4656
4657 ShowWindow(hwnd, SW_SHOW);
4658 flush_events();
4659 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4660
4661 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4662 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4663 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4664 ok(GetActiveWindow() == hwnd, "window should still be active\n");
4665
4666 /* test WM_SETREDRAW on a visible top level window */
4667 ShowWindow(hwnd, SW_SHOW);
4668 flush_events();
4669 test_WM_SETREDRAW(hwnd);
4670
4671 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4672 test_scroll_messages(hwnd);
4673
4674 /* test resizing and moving */
4675 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4676 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4677 flush_events();
4678 flush_sequence();
4679 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4680 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4681 flush_events();
4682 flush_sequence();
4683 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4684 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4685 flush_events();
4686 flush_sequence();
4687
4688 /* popups don't get WM_GETMINMAXINFO */
4689 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4690 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4691 flush_sequence();
4692 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4693 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4694
4695 DestroyWindow(hwnd);
4696 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4697
4698 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4699 100, 100, 200, 200, 0, 0, 0, NULL);
4700 ok (hparent != 0, "Failed to create parent window\n");
4701 flush_sequence();
4702
4703 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4704 0, 0, 10, 10, hparent, 0, 0, NULL);
4705 ok (hchild != 0, "Failed to create child window\n");
4706 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4707 DestroyWindow(hchild);
4708 flush_sequence();
4709
4710 /* visible child window with a caption */
4711 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4712 WS_CHILD | WS_VISIBLE | WS_CAPTION,
4713 0, 0, 10, 10, hparent, 0, 0, NULL);
4714 ok (hchild != 0, "Failed to create child window\n");
4715 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4716
4717 trace("testing scroll APIs on a visible child window %p\n", hchild);
4718 test_scroll_messages(hchild);
4719
4720 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4721 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4722
4723 DestroyWindow(hchild);
4724 flush_sequence();
4725
4726 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4727 0, 0, 10, 10, hparent, 0, 0, NULL);
4728 ok (hchild != 0, "Failed to create child window\n");
4729 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4730
4731 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4732 100, 100, 50, 50, hparent, 0, 0, NULL);
4733 ok (hchild2 != 0, "Failed to create child2 window\n");
4734 flush_sequence();
4735
4736 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4737 0, 100, 50, 50, hchild, 0, 0, NULL);
4738 ok (hbutton != 0, "Failed to create button window\n");
4739
4740 /* test WM_SETREDRAW on a not visible child window */
4741 test_WM_SETREDRAW(hchild);
4742
4743 ShowWindow(hchild, SW_SHOW);
4744 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4745
4746 /* check parent messages too */
4747 log_all_parent_messages++;
4748 ShowWindow(hchild, SW_HIDE);
4749 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4750 log_all_parent_messages--;
4751
4752 ShowWindow(hchild, SW_SHOW);
4753 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4754
4755 ShowWindow(hchild, SW_HIDE);
4756 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4757
4758 ShowWindow(hchild, SW_SHOW);
4759 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4760
4761 /* test WM_SETREDRAW on a visible child window */
4762 test_WM_SETREDRAW(hchild);
4763
4764 log_all_parent_messages++;
4765 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4766 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4767 log_all_parent_messages--;
4768
4769 ShowWindow(hchild, SW_HIDE);
4770 flush_sequence();
4771 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4772 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4773
4774 ShowWindow(hchild, SW_HIDE);
4775 flush_sequence();
4776 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4777 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4778
4779 /* DestroyWindow sequence below expects that a child has focus */
4780 SetFocus(hchild);
4781 flush_sequence();
4782
4783 DestroyWindow(hchild);
4784 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4785 DestroyWindow(hchild2);
4786 DestroyWindow(hbutton);
4787
4788 flush_sequence();
4789 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4790 0, 0, 100, 100, hparent, 0, 0, NULL);
4791 ok (hchild != 0, "Failed to create child popup window\n");
4792 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4793 DestroyWindow(hchild);
4794
4795 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4796 flush_sequence();
4797 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4798 0, 0, 100, 100, hparent, 0, 0, NULL);
4799 ok (hchild != 0, "Failed to create popup window\n");
4800 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4801 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4802 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4803 flush_sequence();
4804 ShowWindow(hchild, SW_SHOW);
4805 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4806 flush_sequence();
4807 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4808 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4809 flush_sequence();
4810 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4811 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4812 DestroyWindow(hchild);
4813
4814 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4815 * changes nothing in message sequences.
4816 */
4817 flush_sequence();
4818 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4819 0, 0, 100, 100, hparent, 0, 0, NULL);
4820 ok (hchild != 0, "Failed to create popup window\n");
4821 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4822 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4823 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4824 flush_sequence();
4825 ShowWindow(hchild, SW_SHOW);
4826 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4827 flush_sequence();
4828 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4829 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4830 DestroyWindow(hchild);
4831
4832 flush_sequence();
4833 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4834 0, 0, 100, 100, hparent, 0, 0, NULL);
4835 ok(hwnd != 0, "Failed to create custom dialog window\n");
4836 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4837
4838 if(0) {
4839 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4840 test_scroll_messages(hwnd);
4841 }
4842
4843 flush_sequence();
4844
4845 test_def_id = TRUE;
4846 SendMessageA(hwnd, WM_NULL, 0, 0);
4847
4848 flush_sequence();
4849 after_end_dialog = TRUE;
4850 EndDialog( hwnd, 0 );
4851 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4852
4853 DestroyWindow(hwnd);
4854 after_end_dialog = FALSE;
4855 test_def_id = FALSE;
4856
4857 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
4858 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
4859
4860 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
4861 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4862 ok(hwnd != 0, "Failed to create custom dialog window\n");
4863 flush_sequence();
4864 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4865 ShowWindow(hwnd, SW_SHOW);
4866 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4867
4868 flush_events();
4869 flush_sequence();
4870 ok(DrawMenuBar(hwnd), "DrawMenuBar failed: %d\n", GetLastError());
4871 flush_events();
4872 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4873 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
4874 DestroyWindow(hwnd);
4875
4876 flush_sequence();
4877 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4878 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4879
4880 DestroyWindow(hparent);
4881 flush_sequence();
4882
4883 /* Message sequence for SetMenu */
4884 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
4885 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
4886 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4887
4888 hmenu = CreateMenu();
4889 ok (hmenu != 0, "Failed to create menu\n");
4890 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4891 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4892 100, 100, 200, 200, 0, hmenu, 0, NULL);
4893 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4894 ok (SetMenu(hwnd, 0), "SetMenu\n");
4895 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4896 ok (SetMenu(hwnd, 0), "SetMenu\n");
4897 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4898 ShowWindow(hwnd, SW_SHOW);
4899 UpdateWindow( hwnd );
4900 flush_events();
4901 flush_sequence();
4902 ok (SetMenu(hwnd, 0), "SetMenu\n");
4903 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4904 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4905 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4906
4907 UpdateWindow( hwnd );
4908 flush_events();
4909 flush_sequence();
4910 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4911 flush_events();
4912 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4913
4914 DestroyWindow(hwnd);
4915 flush_sequence();
4916
4917 /* Message sequence for EnableWindow */
4918 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4919 100, 100, 200, 200, 0, 0, 0, NULL);
4920 ok (hparent != 0, "Failed to create parent window\n");
4921 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4922 0, 0, 10, 10, hparent, 0, 0, NULL);
4923 ok (hchild != 0, "Failed to create child window\n");
4924
4925 SetFocus(hchild);
4926 flush_events();
4927 flush_sequence();
4928
4929 EnableWindow(hparent, FALSE);
4930 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4931
4932 EnableWindow(hparent, TRUE);
4933 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4934
4935 flush_events();
4936 flush_sequence();
4937
4938 test_MsgWaitForMultipleObjects(hparent);
4939
4940 /* the following test causes an exception in user.exe under win9x */
4941 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4942 {
4943 DestroyWindow(hparent);
4944 flush_sequence();
4945 return;
4946 }
4947 PostMessageW( hparent, WM_USER+1, 0, 0 );
4948 /* PeekMessage(NULL) fails, but still removes the message */
4949 SetLastError(0xdeadbeef);
4950 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4951 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4952 GetLastError() == 0xdeadbeef, /* NT4 */
4953 "last error is %d\n", GetLastError() );
4954 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4955 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4956
4957 DestroyWindow(hchild);
4958 DestroyWindow(hparent);
4959 flush_sequence();
4960
4961 /* Message sequences for WM_SETICON */
4962 trace("testing WM_SETICON\n");
4963 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4964 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4965 NULL, NULL, 0);
4966 ShowWindow(hwnd, SW_SHOW);
4967 UpdateWindow(hwnd);
4968 flush_events();
4969 flush_sequence();
4970 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4971 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4972
4973 ShowWindow(hwnd, SW_HIDE);
4974 flush_events();
4975 flush_sequence();
4976 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4977 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4978 DestroyWindow(hwnd);
4979 flush_sequence();
4980
4981 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4982 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4983 NULL, NULL, 0);
4984 ShowWindow(hwnd, SW_SHOW);
4985 UpdateWindow(hwnd);
4986 flush_events();
4987 flush_sequence();
4988 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4989 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4990
4991 ShowWindow(hwnd, SW_HIDE);
4992 flush_events();
4993 flush_sequence();
4994 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4995 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4996
4997 flush_sequence();
4998 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
4999 if (!res)
5000 {
5001 todo_wine win_skip( "Message 0x3b not supported\n" );
5002 goto done;
5003 }
5004 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5005 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5006 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5007 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5008 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5009 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5010 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5011 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5012
5013 flush_sequence();
5014 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5015 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5016 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5017 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5018 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5019 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5020
5021 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5022 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5023 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5024
5025 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5026 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5027 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5028
5029 done:
5030 DestroyWindow(hwnd);
5031 flush_sequence();
5032 }
5033
5034 static void test_setwindowpos(void)
5035 {
5036 HWND hwnd;
5037 RECT rc;
5038 LRESULT res;
5039 const INT winX = 100;
5040 const INT winY = 100;
5041 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5042
5043 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5044 0, 0, winX, winY, 0,
5045 NULL, NULL, 0);
5046
5047 GetWindowRect(hwnd, &rc);
5048 expect(sysX, rc.right);
5049 expect(winY, rc.bottom);
5050
5051 flush_events();
5052 flush_sequence();
5053 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5054 ok_sequence(WmZOrder, "Z-Order", TRUE);
5055 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5056
5057 GetWindowRect(hwnd, &rc);
5058 expect(sysX, rc.right);
5059 expect(winY, rc.bottom);
5060 DestroyWindow(hwnd);
5061 }
5062
5063 static void invisible_parent_tests(void)
5064 {
5065 HWND hparent, hchild;
5066
5067 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5068 100, 100, 200, 200, 0, 0, 0, NULL);
5069 ok (hparent != 0, "Failed to create parent window\n");
5070 flush_sequence();
5071
5072 /* test showing child with hidden parent */
5073
5074 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5075 0, 0, 10, 10, hparent, 0, 0, NULL);
5076 ok (hchild != 0, "Failed to create child window\n");
5077 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5078
5079 ShowWindow( hchild, SW_MINIMIZE );
5080 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5081 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5082 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5083
5084 /* repeat */
5085 flush_events();
5086 flush_sequence();
5087 ShowWindow( hchild, SW_MINIMIZE );
5088 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5089
5090 DestroyWindow(hchild);
5091 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5092 0, 0, 10, 10, hparent, 0, 0, NULL);
5093 flush_sequence();
5094
5095 ShowWindow( hchild, SW_MAXIMIZE );
5096 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5097 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5098 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5099
5100 /* repeat */
5101 flush_events();
5102 flush_sequence();
5103 ShowWindow( hchild, SW_MAXIMIZE );
5104 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5105
5106 DestroyWindow(hchild);
5107 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5108 0, 0, 10, 10, hparent, 0, 0, NULL);
5109 flush_sequence();
5110
5111 ShowWindow( hchild, SW_RESTORE );
5112 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5113 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5114 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5115
5116 DestroyWindow(hchild);
5117 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5118 0, 0, 10, 10, hparent, 0, 0, NULL);
5119 flush_sequence();
5120
5121 ShowWindow( hchild, SW_SHOWMINIMIZED );
5122 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5123 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5124 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5125
5126 /* repeat */
5127 flush_events();
5128 flush_sequence();
5129 ShowWindow( hchild, SW_SHOWMINIMIZED );
5130 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5131
5132 DestroyWindow(hchild);
5133 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5134 0, 0, 10, 10, hparent, 0, 0, NULL);
5135 flush_sequence();
5136
5137 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5138 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5139 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5140 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5141 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5142
5143 DestroyWindow(hchild);
5144 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5145 0, 0, 10, 10, hparent, 0, 0, NULL);
5146 flush_sequence();
5147
5148 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5149 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5150 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5151 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5152
5153 /* repeat */
5154 flush_events();
5155 flush_sequence();
5156 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5157 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5158
5159 DestroyWindow(hchild);
5160 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5161 0, 0, 10, 10, hparent, 0, 0, NULL);
5162 flush_sequence();
5163
5164 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5165 ShowWindow( hchild, SW_FORCEMINIMIZE );
5166 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5167 todo_wine {
5168 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5169 }
5170 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5171
5172 DestroyWindow(hchild);
5173 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5174 0, 0, 10, 10, hparent, 0, 0, NULL);
5175 flush_sequence();
5176
5177 ShowWindow( hchild, SW_SHOWNA );
5178 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5179 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5180 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5181
5182 /* repeat */
5183 flush_events();
5184 flush_sequence();
5185 ShowWindow( hchild, SW_SHOWNA );
5186 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5187
5188 DestroyWindow(hchild);
5189 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5190 0, 0, 10, 10, hparent, 0, 0, NULL);
5191 flush_sequence();
5192
5193 ShowWindow( hchild, SW_SHOW );
5194 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5195 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5196 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5197
5198 /* repeat */
5199 flush_events();
5200 flush_sequence();
5201 ShowWindow( hchild, SW_SHOW );
5202 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5203
5204 ShowWindow( hchild, SW_HIDE );
5205 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5206 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5207 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5208
5209 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5210 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5211 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5212 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5213
5214 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5215 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5216 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5217 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5218
5219 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5220 flush_sequence();
5221 DestroyWindow(hchild);
5222 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5223
5224 DestroyWindow(hparent);
5225 flush_sequence();
5226 }
5227
5228 /****************** button message test *************************/
5229 #define ID_BUTTON 0x000e
5230
5231 static const struct message WmSetFocusButtonSeq[] =
5232 {
5233 { HCBT_SETFOCUS, hook },
5234 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5235 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5236 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5237 { WM_SETFOCUS, sent|wparam, 0 },
5238 { WM_CTLCOLORBTN, sent|parent },
5239 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5240 { WM_APP, sent|wparam|lparam, 0, 0 },
5241 { 0 }
5242 };
5243 static const struct message WmKillFocusButtonSeq[] =
5244 {
5245 { HCBT_SETFOCUS, hook },
5246 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5247 { WM_KILLFOCUS, sent|wparam, 0 },
5248 { WM_CTLCOLORBTN, sent|parent },
5249 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5250 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5251 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5252 { WM_APP, sent|wparam|lparam, 0, 0 },
5253 { WM_PAINT, sent },
5254 { WM_CTLCOLORBTN, sent|parent },
5255 { 0 }
5256 };
5257 static const struct message WmSetFocusStaticSeq[] =
5258 {
5259 { HCBT_SETFOCUS, hook },
5260 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5261 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5262 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5263 { WM_SETFOCUS, sent|wparam, 0 },
5264 { WM_CTLCOLORSTATIC, sent|parent },
5265 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5266 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5267 { WM_APP, sent|wparam|lparam, 0, 0 },
5268 { 0 }
5269 };
5270 static const struct message WmKillFocusStaticSeq[] =
5271 {
5272 { HCBT_SETFOCUS, hook },
5273 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5274 { WM_KILLFOCUS, sent|wparam, 0 },
5275 { WM_CTLCOLORSTATIC, sent|parent },
5276 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5277 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5278 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5279 { WM_APP, sent|wparam|lparam, 0, 0 },
5280 { WM_PAINT, sent },
5281 { WM_CTLCOLORSTATIC, sent|parent },
5282 { 0 }
5283 };
5284 static const struct message WmSetFocusOwnerdrawSeq[] =
5285 {
5286 { HCBT_SETFOCUS, hook },
5287 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5288 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5289 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5290 { WM_SETFOCUS, sent|wparam, 0 },
5291 { WM_CTLCOLORBTN, sent|parent },
5292 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5293 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5294 { WM_APP, sent|wparam|lparam, 0, 0 },
5295 { 0 }
5296 };
5297 static const struct message WmKillFocusOwnerdrawSeq[] =
5298 {
5299 { HCBT_SETFOCUS, hook },
5300 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5301 { WM_KILLFOCUS, sent|wparam, 0 },
5302 { WM_CTLCOLORBTN, sent|parent },
5303 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5304 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5305 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5306 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5307 { WM_APP, sent|wparam|lparam, 0, 0 },
5308 { WM_PAINT, sent },
5309 { WM_CTLCOLORBTN, sent|parent },
5310 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5311 { 0 }
5312 };
5313 static const struct message WmLButtonDownSeq[] =
5314 {
5315 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5316 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5317 { HCBT_SETFOCUS, hook },
5318 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5319 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5320 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5321 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5322 { WM_CTLCOLORBTN, sent|defwinproc },
5323 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5324 { WM_CTLCOLORBTN, sent|defwinproc },
5325 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5326 { 0 }
5327 };
5328 static const struct message WmLButtonUpSeq[] =
5329 {
5330 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5331 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5332 { WM_CTLCOLORBTN, sent|defwinproc },
5333 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5334 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5335 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5336 { 0 }
5337 };
5338 static const struct message WmSetFontButtonSeq[] =
5339 {
5340 { WM_SETFONT, sent },
5341 { WM_PAINT, sent },
5342 { WM_ERASEBKGND, sent|defwinproc|optional },
5343 { WM_CTLCOLORBTN, sent|defwinproc },
5344 { 0 }
5345 };
5346 static const struct message WmSetStyleButtonSeq[] =
5347 {
5348 { BM_SETSTYLE, sent },
5349 { WM_APP, sent|wparam|lparam, 0, 0 },
5350 { WM_PAINT, sent },
5351 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5352 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5353 { WM_CTLCOLORBTN, sent|parent },
5354 { 0 }
5355 };
5356 static const struct message WmSetStyleStaticSeq[] =
5357 {
5358 { BM_SETSTYLE, sent },
5359 { WM_APP, sent|wparam|lparam, 0, 0 },
5360 { WM_PAINT, sent },
5361 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5362 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5363 { WM_CTLCOLORSTATIC, sent|parent },
5364 { 0 }
5365 };
5366 static const struct message WmSetStyleUserSeq[] =
5367 {
5368 { BM_SETSTYLE, sent },
5369 { WM_APP, sent|wparam|lparam, 0, 0 },
5370 { WM_PAINT, sent },
5371 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5372 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5373 { WM_CTLCOLORBTN, sent|parent },
5374 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5375 { 0 }
5376 };
5377 static const struct message WmSetStyleOwnerdrawSeq[] =
5378 {
5379 { BM_SETSTYLE, sent },
5380 { WM_APP, sent|wparam|lparam, 0, 0 },
5381 { WM_PAINT, sent },
5382 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5383 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5384 { WM_CTLCOLORBTN, sent|parent },
5385 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5386 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5387 { 0 }
5388 };
5389 static const struct message WmSetStateButtonSeq[] =
5390 {
5391 { BM_SETSTATE, sent },
5392 { WM_CTLCOLORBTN, sent|parent },
5393 { WM_APP, sent|wparam|lparam, 0, 0 },
5394 { 0 }
5395 };
5396 static const struct message WmSetStateStaticSeq[] =
5397 {
5398 { BM_SETSTATE, sent },
5399 { WM_CTLCOLORSTATIC, sent|parent },
5400 { WM_APP, sent|wparam|lparam, 0, 0 },
5401 { 0 }
5402 };
5403 static const struct message WmSetStateUserSeq[] =
5404 {
5405 { BM_SETSTATE, sent },
5406 { WM_CTLCOLORBTN, sent|parent },
5407 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
5408 { WM_APP, sent|wparam|lparam, 0, 0 },
5409 { 0 }
5410 };
5411 static const struct message WmSetStateOwnerdrawSeq[] =
5412 {
5413 { BM_SETSTATE, sent },
5414 { WM_CTLCOLORBTN, sent|parent },
5415 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
5416 { WM_APP, sent|wparam|lparam, 0, 0 },
5417 { 0 }
5418 };
5419 static const struct message WmClearStateButtonSeq[] =
5420 {
5421 { BM_SETSTATE, sent },
5422 { WM_CTLCOLORBTN, sent|parent },
5423 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
5424 { WM_APP, sent|wparam|lparam, 0, 0 },
5425 { 0 }
5426 };
5427 static const struct message WmClearStateOwnerdrawSeq[] =
5428 {
5429 { BM_SETSTATE, sent },
5430 { WM_CTLCOLORBTN, sent|parent },
5431 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
5432 { WM_APP, sent|wparam|lparam, 0, 0 },
5433 { 0 }
5434 };
5435 static const struct message WmSetCheckIgnoredSeq[] =
5436 {
5437 { BM_SETCHECK, sent },
5438 { WM_APP, sent|wparam|lparam, 0, 0 },
5439 { 0 }
5440 };
5441 static const struct message WmSetCheckStaticSeq[] =
5442 {
5443 { BM_SETCHECK, sent },
5444 { WM_CTLCOLORSTATIC, sent|parent },
5445 { WM_APP, sent|wparam|lparam, 0, 0 },
5446 { 0 }
5447 };
5448
5449 static WNDPROC old_button_proc;
5450
5451 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5452 {
5453 static LONG defwndproc_counter = 0;
5454 LRESULT ret;
5455 struct recvd_message msg;
5456
5457 if (ignore_message( message )) return 0;
5458
5459 switch (message)
5460 {
5461 case WM_SYNCPAINT:
5462 break;
5463 case BM_SETSTATE:
5464 if (GetCapture())
5465 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5466 /* fall through */
5467 default:
5468 msg.hwnd = hwnd;
5469 msg.message = message;
5470 msg.flags = sent|wparam|lparam;
5471 if (defwndproc_counter) msg.flags |= defwinproc;
5472 msg.wParam = wParam;
5473 msg.lParam = lParam;
5474 msg.descr = "button";
5475 add_message(&msg);
5476 }
5477
5478 defwndproc_counter++;
5479 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5480 defwndproc_counter--;
5481
5482 return ret;
5483 }
5484
5485 static void subclass_button(void)
5486 {
5487 WNDCLASSA cls;
5488
5489 if (!GetClassInfoA(0, "button", &cls)) assert(0);
5490
5491 old_button_proc = cls.lpfnWndProc;
5492
5493 cls.hInstance = GetModuleHandleA(NULL);
5494 cls.lpfnWndProc = button_hook_proc;
5495 cls.lpszClassName = "my_button_class";
5496 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5497 if (!RegisterClassA(&cls)) assert(0);
5498 }
5499
5500 static void test_button_messages(void)
5501 {
5502 static const struct
5503 {
5504 DWORD style;
5505 DWORD dlg_code;
5506 const struct message *setfocus;
5507 const struct message *killfocus;
5508 const struct message *setstyle;
5509 const struct message *setstate;
5510 const struct message *clearstate;
5511 const struct message *setcheck;
5512 } button[] = {
5513 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5514 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5515 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5516 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5517 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5518 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5519 { BS_CHECKBOX, DLGC_BUTTON,
5520 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5521 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5522 { BS_AUTOCHECKBOX, DLGC_BUTTON,
5523 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5524 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5525 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5526 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5527 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5528 { BS_3STATE, DLGC_BUTTON,
5529 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5530 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5531 { BS_AUTO3STATE, DLGC_BUTTON,
5532 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5533 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5534 { BS_GROUPBOX, DLGC_STATIC,
5535 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5536 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
5537 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5538 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
5539 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
5540 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5541 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5542 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5543 { BS_OWNERDRAW, DLGC_BUTTON,
5544 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
5545 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
5546 };
5547 unsigned int i;
5548 HWND hwnd, parent;
5549 DWORD dlg_code;
5550 HFONT zfont;
5551
5552 /* selection with VK_SPACE should capture button window */
5553 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5554 0, 0, 50, 14, 0, 0, 0, NULL);
5555 ok(hwnd != 0, "Failed to create button window\n");
5556 ReleaseCapture();
5557 SetFocus(hwnd);
5558 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5559 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5560 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5561 DestroyWindow(hwnd);
5562
5563 subclass_button();
5564
5565 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5566 100, 100, 200, 200, 0, 0, 0, NULL);
5567 ok(parent != 0, "Failed to create parent window\n");
5568
5569 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5570 {
5571 MSG msg;
5572 DWORD style, state;
5573
5574 trace("button style %08x\n", button[i].style);
5575
5576 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5577 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5578 ok(hwnd != 0, "Failed to create button window\n");
5579
5580 style = GetWindowLongA(hwnd, GWL_STYLE);
5581 style &= ~(WS_CHILD | BS_NOTIFY);
5582 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5583 if (button[i].style == BS_USERBUTTON)
5584 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5585 else
5586 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5587
5588 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5589 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5590
5591 ShowWindow(hwnd, SW_SHOW);
5592 UpdateWindow(hwnd);
5593 SetFocus(0);
5594 flush_events();
5595 SetFocus(0);
5596 flush_sequence();
5597
5598 log_all_parent_messages++;
5599
5600 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5601 SetFocus(hwnd);
5602 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5603 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5604 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5605
5606 SetFocus(0);
5607 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5608 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5609 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5610
5611 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5612
5613 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5614 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5615 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5616 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5617
5618 style = GetWindowLongA(hwnd, GWL_STYLE);
5619 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5620 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5621 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5622
5623 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5624 ok(state == 0, "expected state 0, got %04x\n", state);
5625
5626 flush_sequence();
5627
5628 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
5629 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5630 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5631 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
5632
5633 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5634 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
5635
5636 style = GetWindowLongA(hwnd, GWL_STYLE);
5637 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5638 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5639
5640 flush_sequence();
5641
5642 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
5643 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5644 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5645 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
5646
5647 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5648 ok(state == 0, "expected state 0, got %04x\n", state);
5649
5650 style = GetWindowLongA(hwnd, GWL_STYLE);
5651 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5652 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5653
5654 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5655 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5656
5657 flush_sequence();
5658
5659 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
5660 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5661 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5662 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
5663
5664 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5665 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5666
5667 style = GetWindowLongA(hwnd, GWL_STYLE);
5668 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5669 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5670
5671 flush_sequence();
5672
5673 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
5674 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5675 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5676 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
5677
5678 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5679 if (button[i].style == BS_PUSHBUTTON ||
5680 button[i].style == BS_DEFPUSHBUTTON ||
5681 button[i].style == BS_GROUPBOX ||
5682 button[i].style == BS_USERBUTTON ||
5683 button[i].style == BS_OWNERDRAW)
5684 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
5685 else
5686 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
5687
5688 style = GetWindowLongA(hwnd, GWL_STYLE);
5689 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5690 if (button[i].style == BS_RADIOBUTTON ||
5691 button[i].style == BS_AUTORADIOBUTTON)
5692 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
5693 else
5694 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5695
5696 log_all_parent_messages--;
5697
5698 DestroyWindow(hwnd);
5699 }
5700
5701 DestroyWindow(parent);
5702
5703 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5704 0, 0, 50, 14, 0, 0, 0, NULL);
5705 ok(hwnd != 0, "Failed to create button window\n");
5706
5707 SetForegroundWindow(hwnd);
5708 flush_events();
5709
5710 SetActiveWindow(hwnd);
5711 SetFocus(0);
5712 flush_sequence();
5713
5714 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5715 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5716
5717 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5718 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5719
5720 flush_sequence();
5721 zfont = GetStockObject(SYSTEM_FONT);
5722 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5723 UpdateWindow(hwnd);
5724 ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5725
5726 DestroyWindow(hwnd);
5727 }
5728
5729 /****************** static message test *************************/
5730 static const struct message WmSetFontStaticSeq[] =
5731 {
5732 { WM_SETFONT, sent },
5733 { WM_PAINT, sent|defwinproc|optional },
5734 { WM_ERASEBKGND, sent|defwinproc|optional },
5735 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5736 { 0 }
5737 };
5738
5739 static WNDPROC old_static_proc;
5740
5741 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5742 {
5743 static LONG defwndproc_counter = 0;
5744 LRESULT ret;
5745 struct recvd_message msg;
5746
5747 if (ignore_message( message )) return 0;
5748
5749 msg.hwnd = hwnd;
5750 msg.message = message;
5751 msg.flags = sent|wparam|lparam;
5752 if (defwndproc_counter) msg.flags |= defwinproc;
5753 msg.wParam = wParam;
5754 msg.lParam = lParam;
5755 msg.descr = "static";
5756 add_message(&msg);
5757
5758 defwndproc_counter++;
5759 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5760 defwndproc_counter--;
5761
5762 return ret;
5763 }
5764
5765 static void subclass_static(void)
5766 {
5767 WNDCLASSA cls;
5768
5769 if (!GetClassInfoA(0, "static", &cls)) assert(0);
5770
5771 old_static_proc = cls.lpfnWndProc;
5772
5773 cls.hInstance = GetModuleHandleA(NULL);
5774 cls.lpfnWndProc = static_hook_proc;
5775 cls.lpszClassName = "my_static_class";
5776 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5777 if (!RegisterClassA(&cls)) assert(0);
5778 }
5779
5780 static void test_static_messages(void)
5781 {
5782 /* FIXME: make as comprehensive as the button message test */
5783 static const struct
5784 {
5785 DWORD style;
5786 DWORD dlg_code;
5787 const struct message *setfont;
5788 } static_ctrl[] = {
5789 { SS_LEFT, DLGC_STATIC,
5790 WmSetFontStaticSeq }
5791 };
5792 unsigned int i;
5793 HWND hwnd;
5794 DWORD dlg_code;
5795
5796 subclass_static();
5797
5798 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5799 {
5800 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5801 0, 0, 50, 14, 0, 0, 0, NULL);
5802 ok(hwnd != 0, "Failed to create static window\n");
5803
5804 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5805 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5806
5807 ShowWindow(hwnd, SW_SHOW);
5808 UpdateWindow(hwnd);
5809 SetFocus(0);
5810 flush_sequence();
5811
5812 trace("static style %08x\n", static_ctrl[i].style);
5813 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5814 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5815
5816 DestroyWindow(hwnd);
5817 }
5818 }
5819
5820 /****************** ComboBox message test *************************/
5821 #define ID_COMBOBOX 0x000f
5822
5823 static const struct message WmKeyDownComboSeq[] =
5824 {
5825 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5826 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5827 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5828 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5829 { WM_CTLCOLOREDIT, sent|parent },
5830 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5831 { 0 }
5832 };
5833
5834 static const struct message WmSetPosComboSeq[] =
5835 {
5836 { WM_WINDOWPOSCHANGING, sent },
5837 { WM_NCCALCSIZE, sent|wparam, TRUE },
5838 { WM_CHILDACTIVATE, sent },
5839 { WM_WINDOWPOSCHANGED, sent },
5840 { WM_MOVE, sent|defwinproc },
5841 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5842 { WM_WINDOWPOSCHANGING, sent|defwinproc },
5843 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
5844 { WM_WINDOWPOSCHANGED, sent|defwinproc },
5845 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5846 { 0 }
5847 };
5848
5849 static WNDPROC old_combobox_proc;
5850
5851 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5852 {
5853 static LONG defwndproc_counter = 0;
5854 LRESULT ret;
5855 struct recvd_message msg;
5856
5857 /* do not log painting messages */
5858 if (message != WM_PAINT &&
5859 message != WM_NCPAINT &&
5860 message != WM_SYNCPAINT &&
5861 message != WM_ERASEBKGND &&
5862 message != WM_NCHITTEST &&
5863 message != WM_GETTEXT &&
5864 !ignore_message( message ))
5865 {
5866 msg.hwnd = hwnd;
5867 msg.message = message;
5868 msg.flags = sent|wparam|lparam;
5869 if (defwndproc_counter) msg.flags |= defwinproc;
5870 msg.wParam = wParam;
5871 msg.lParam = lParam;
5872 msg.descr = "combo";
5873 add_message(&msg);
5874 }
5875
5876 defwndproc_counter++;
5877 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5878 defwndproc_counter--;
5879
5880 return ret;
5881 }
5882
5883 static void subclass_combobox(void)
5884 {
5885 WNDCLASSA cls;
5886
5887 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5888
5889 old_combobox_proc = cls.lpfnWndProc;
5890
5891 cls.hInstance = GetModuleHandleA(NULL);
5892 cls.lpfnWndProc = combobox_hook_proc;
5893 cls.lpszClassName = "my_combobox_class";
5894 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5895 if (!RegisterClassA(&cls)) assert(0);
5896 }
5897
5898 static void test_combobox_messages(void)
5899 {
5900 HWND parent, combo;
5901 LRESULT ret;
5902
5903 subclass_combobox();
5904
5905 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5906 100, 100, 200, 200, 0, 0, 0, NULL);
5907 ok(parent != 0, "Failed to create parent window\n");
5908 flush_sequence();
5909
5910 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5911 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5912 ok(combo != 0, "Failed to create combobox window\n");
5913
5914 UpdateWindow(combo);
5915
5916 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
5917 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5918
5919 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5920 ok(ret == 0, "expected 0, got %ld\n", ret);
5921 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5922 ok(ret == 1, "expected 1, got %ld\n", ret);
5923 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5924 ok(ret == 2, "expected 2, got %ld\n", ret);
5925
5926 SendMessageA(combo, CB_SETCURSEL, 0, 0);
5927 SetFocus(combo);
5928 flush_sequence();
5929
5930 log_all_parent_messages++;
5931 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
5932 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
5933 log_all_parent_messages--;
5934 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5935
5936 flush_sequence();
5937 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
5938 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
5939
5940 DestroyWindow(combo);
5941 DestroyWindow(parent);
5942 }
5943
5944 /****************** WM_IME_KEYDOWN message test *******************/
5945
5946 static const struct message WmImeKeydownMsgSeq_0[] =
5947 {
5948 { WM_IME_KEYDOWN, wparam, VK_RETURN },
5949 { WM_CHAR, wparam, 'A' },
5950 { 0 }
5951 };
5952
5953 static const struct message WmImeKeydownMsgSeq_1[] =
5954 {
5955 { WM_KEYDOWN, optional|wparam, VK_RETURN },
5956 { WM_CHAR, optional|wparam, VK_RETURN },
5957 { 0 }
5958 };
5959
5960 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5961 {
5962 struct recvd_message msg;
5963
5964 msg.hwnd = hwnd;
5965 msg.message = message;
5966 msg.flags = wparam|lparam;
5967 msg.wParam = wParam;
5968 msg.lParam = lParam;
5969 msg.descr = "wmime_keydown";
5970 add_message(&msg);
5971
5972 return DefWindowProcA(hwnd, message, wParam, lParam);
5973 }
5974
5975 static void register_wmime_keydown_class(void)
5976 {
5977 WNDCLASSA cls;
5978
5979 ZeroMemory(&cls, sizeof(WNDCLASSA));
5980 cls.lpfnWndProc = wmime_keydown_procA;
5981 cls.hInstance = GetModuleHandleA(0);
5982 cls.lpszClassName = "wmime_keydown_class";
5983 if (!RegisterClassA(&cls)) assert(0);
5984 }
5985
5986 static void test_wmime_keydown_message(void)
5987 {
5988 HWND hwnd;
5989 MSG msg;
5990
5991 trace("Message sequences by WM_IME_KEYDOWN\n");
5992
5993 register_wmime_keydown_class();
5994 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5995 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5996 NULL, NULL, 0);
5997 flush_events();
5998 flush_sequence();
5999
6000 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
6001 SendMessageA(hwnd, WM_CHAR, 'A', 1);
6002 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
6003
6004 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
6005 {
6006 TranslateMessage(&msg);
6007 DispatchMessageA(&msg);
6008 }
6009 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
6010
6011 DestroyWindow(hwnd);
6012 }
6013
6014 /************* painting message test ********************/
6015
6016 void dump_region(HRGN hrgn)
6017 {
6018 DWORD i, size;
6019 RGNDATA *data = NULL;
6020 RECT *rect;
6021
6022 if (!hrgn)
6023 {
6024 printf( "null region\n" );
6025 return;
6026 }
6027 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
6028 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
6029 GetRegionData( hrgn, size, data );
6030 printf("%d rects:", data->rdh.nCount );
6031 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
6032 printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
6033 printf("\n");
6034 HeapFree( GetProcessHeap(), 0, data );
6035 }
6036
6037 static void check_update_rgn( HWND hwnd, HRGN hrgn )
6038 {
6039 INT ret;
6040 RECT r1, r2;
6041 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
6042 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
6043
6044 ret = GetUpdateRgn( hwnd, update, FALSE );
6045 ok( ret != ERROR, "GetUpdateRgn failed\n" );
6046 if (ret == NULLREGION)
6047 {
6048 ok( !hrgn, "Update region shouldn't be empty\n" );
6049 }
6050 else
6051 {
6052 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
6053 {
6054 ok( 0, "Regions are different\n" );
6055 if (winetest_debug > 0)
6056 {
6057 printf( "Update region: " );
6058 dump_region( update );
6059 printf( "Wanted region: " );
6060 dump_region( hrgn );
6061 }
6062 }
6063 }
6064 GetRgnBox( update, &r1 );
6065 GetUpdateRect( hwnd, &r2, FALSE );
6066 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
6067 "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
6068 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
6069
6070 DeleteObject( tmp );
6071 DeleteObject( update );
6072 }
6073
6074 static const struct message WmInvalidateRgn[] = {
6075 { WM_NCPAINT, sent },
6076 { WM_GETTEXT, sent|defwinproc|optional },
6077 { 0 }
6078 };
6079
6080 static const struct message WmGetUpdateRect[] = {
6081 { WM_NCPAINT, sent },
6082 { WM_GETTEXT, sent|defwinproc|optional },
6083 { WM_PAINT, sent },
6084 { 0 }
6085 };
6086
6087 static const struct message WmInvalidateFull[] = {
6088 { WM_NCPAINT, sent|wparam, 1 },
6089 { WM_GETTEXT, sent|defwinproc|optional },
6090 { 0 }
6091 };
6092
6093 static const struct message WmInvalidateErase[] = {
6094 { WM_NCPAINT, sent|wparam, 1 },
6095 { WM_GETTEXT, sent|defwinproc|optional },
6096 { WM_ERASEBKGND, sent },
6097 { 0 }
6098 };
6099
6100 static const struct message WmInvalidatePaint[] = {
6101 { WM_PAINT, sent },
6102 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
6103 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6104 { 0 }
6105 };
6106
6107 static const struct message WmInvalidateErasePaint[] = {
6108 { WM_PAINT, sent },
6109 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
6110 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6111 { WM_ERASEBKGND, sent|beginpaint|optional },
6112 { 0 }
6113 };
6114
6115 static const struct message WmInvalidateErasePaint2[] = {
6116 { WM_PAINT, sent },
6117 { WM_NCPAINT, sent|beginpaint },
6118 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6119 { WM_ERASEBKGND, sent|beginpaint|optional },
6120 { 0 }
6121 };
6122
6123 static const struct message WmErase[] = {
6124 { WM_ERASEBKGND, sent },
6125 { 0 }
6126 };
6127
6128 static const struct message WmPaint[] = {
6129 { WM_PAINT, sent },
6130 { 0 }
6131 };
6132
6133 static const struct message WmParentOnlyPaint[] = {
6134 { WM_PAINT, sent|parent },
6135 { 0 }
6136 };
6137
6138 static const struct message WmInvalidateParent[] = {
6139 { WM_NCPAINT, sent|parent },
6140 { WM_GETTEXT, sent|defwinproc|parent|optional },
6141 { WM_ERASEBKGND, sent|parent },
6142 { 0 }
6143 };
6144
6145 static const struct message WmInvalidateParentChild[] = {
6146 { WM_NCPAINT, sent|parent },
6147 { WM_GETTEXT, sent|defwinproc|parent|optional },
6148 { WM_ERASEBKGND, sent|parent },
6149 { WM_NCPAINT, sent },
6150 { WM_GETTEXT, sent|defwinproc|optional },
6151 { WM_ERASEBKGND, sent },
6152 { 0 }
6153 };
6154
6155 static const struct message WmInvalidateParentChild2[] = {
6156 { WM_ERASEBKGND, sent|parent },
6157 { WM_NCPAINT, sent },
6158 { WM_GETTEXT, sent|defwinproc|optional },
6159 { WM_ERASEBKGND, sent },
6160 { 0 }
6161 };
6162
6163 static const struct message WmParentPaint[] = {
6164 { WM_PAINT, sent|parent },
6165 { WM_PAINT, sent },
6166 { 0 }
6167 };
6168
6169 static const struct message WmParentPaintNc[] = {
6170 { WM_PAINT, sent|parent },
6171 { WM_PAINT, sent },
6172 { WM_NCPAINT, sent|beginpaint },
6173 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6174 { WM_ERASEBKGND, sent|beginpaint|optional },
6175 { 0 }
6176 };
6177
6178 static const struct message WmChildPaintNc[] = {
6179 { WM_PAINT, sent },
6180 { WM_NCPAINT, sent|beginpaint },
6181 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6182 { WM_ERASEBKGND, sent|beginpaint|optional },
6183 { 0 }
6184 };
6185
6186 static const struct message WmParentErasePaint[] = {
6187 { WM_PAINT, sent|parent },
6188 { WM_NCPAINT, sent|parent|beginpaint },
6189 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6190 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
6191 { WM_PAINT, sent },
6192 { WM_NCPAINT, sent|beginpaint },
6193 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6194 { WM_ERASEBKGND, sent|beginpaint|optional },
6195 { 0 }
6196 };
6197
6198 static const struct message WmParentOnlyNcPaint[] = {
6199 { WM_PAINT, sent|parent },
6200 { WM_NCPAINT, sent|parent|beginpaint },
6201 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6202 { 0 }
6203 };
6204
6205 static const struct message WmSetParentStyle[] = {
6206 { WM_STYLECHANGING, sent|parent },
6207 { WM_STYLECHANGED, sent|parent },
6208 { 0 }
6209 };
6210
6211 static void test_paint_messages(void)
6212 {
6213 BOOL ret;
6214 RECT rect;
6215 POINT pt;
6216 MSG msg;
6217 HWND hparent, hchild;
6218 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6219 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
6220 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
6221 100, 100, 200, 200, 0, 0, 0, NULL);
6222 ok (hwnd != 0, "Failed to create overlapped window\n");
6223
6224 ShowWindow( hwnd, SW_SHOW );
6225 UpdateWindow( hwnd );
6226 flush_events();
6227 flush_sequence();
6228
6229 check_update_rgn( hwnd, 0 );
6230 SetRectRgn( hrgn, 10, 10, 20, 20 );
6231 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6232 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6233 check_update_rgn( hwnd, hrgn );
6234 SetRectRgn( hrgn2, 20, 20, 30, 30 );
6235 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
6236 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6237 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
6238 check_update_rgn( hwnd, hrgn );
6239 /* validate everything */
6240 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6241 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6242 check_update_rgn( hwnd, 0 );
6243
6244 /* test empty region */
6245 SetRectRgn( hrgn, 10, 10, 10, 15 );
6246 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6247 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6248 check_update_rgn( hwnd, 0 );
6249 /* test empty rect */
6250 SetRect( &rect, 10, 10, 10, 15 );
6251 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
6252 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6253 check_update_rgn( hwnd, 0 );
6254
6255 /* flush pending messages */
6256 flush_events();
6257 flush_sequence();
6258
6259 GetClientRect( hwnd, &rect );
6260 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
6261 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
6262 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6263 */
6264 trace("testing InvalidateRect(0, NULL, FALSE)\n");
6265 SetRectEmpty( &rect );
6266 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
6267 check_update_rgn( hwnd, hrgn );
6268 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6269 flush_events();
6270 ok_sequence( WmPaint, "Paint", FALSE );
6271 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6272 check_update_rgn( hwnd, 0 );
6273
6274 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
6275 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6276 */
6277 trace("testing ValidateRect(0, NULL)\n");
6278 SetRectEmpty( &rect );
6279 if (ValidateRect(0, &rect)) /* not supported on Win9x */
6280 {
6281 check_update_rgn( hwnd, hrgn );
6282 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6283 flush_events();
6284 ok_sequence( WmPaint, "Paint", FALSE );
6285 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6286 check_update_rgn( hwnd, 0 );
6287 }
6288
6289 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
6290 SetLastError(0xdeadbeef);
6291 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
6292 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
6293 "wrong error code %d\n", GetLastError());
6294 check_update_rgn( hwnd, 0 );
6295 flush_events();
6296 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6297
6298 trace("testing ValidateRgn(0, NULL)\n");
6299 SetLastError(0xdeadbeef);
6300 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6301 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6302 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6303 "wrong error code %d\n", GetLastError());
6304 check_update_rgn( hwnd, 0 );
6305 flush_events();
6306 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6307
6308 trace("testing UpdateWindow(NULL)\n");
6309 SetLastError(0xdeadbeef);
6310 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
6311 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6312 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6313 "wrong error code %d\n", GetLastError());
6314 check_update_rgn( hwnd, 0 );
6315 flush_events();
6316 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6317
6318 /* now with frame */
6319 SetRectRgn( hrgn, -5, -5, 20, 20 );
6320
6321 /* flush pending messages */
6322 flush_events();
6323 flush_sequence();
6324 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6325 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6326
6327 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
6328 check_update_rgn( hwnd, hrgn );
6329
6330 flush_sequence();
6331 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6332 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6333
6334 flush_sequence();
6335 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6336 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6337
6338 GetClientRect( hwnd, &rect );
6339 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6340 check_update_rgn( hwnd, hrgn );
6341
6342 flush_sequence();
6343 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6344 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6345
6346 flush_sequence();
6347 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6348 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6349 check_update_rgn( hwnd, 0 );
6350
6351 flush_sequence();
6352 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6353 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6354 check_update_rgn( hwnd, 0 );
6355
6356 flush_sequence();
6357 SetRectRgn( hrgn, 0, 0, 100, 100 );
6358 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6359 SetRectRgn( hrgn, 0, 0, 50, 100 );
6360 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6361 SetRectRgn( hrgn, 50, 0, 100, 100 );
6362 check_update_rgn( hwnd, hrgn );
6363 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6364 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
6365 check_update_rgn( hwnd, 0 );
6366
6367 flush_sequence();
6368 SetRectRgn( hrgn, 0, 0, 100, 100 );
6369 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6370 SetRectRgn( hrgn, 0, 0, 100, 50 );
6371 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6372 ok_sequence( WmErase, "Erase", FALSE );
6373 SetRectRgn( hrgn, 0, 50, 100, 100 );
6374 check_update_rgn( hwnd, hrgn );
6375
6376 flush_sequence();
6377 SetRectRgn( hrgn, 0, 0, 100, 100 );
6378 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6379 SetRectRgn( hrgn, 0, 0, 50, 50 );
6380 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6381 ok_sequence( WmPaint, "Paint", FALSE );
6382
6383 flush_sequence();
6384 SetRectRgn( hrgn, -4, -4, -2, -2 );
6385 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6386 SetRectRgn( hrgn, -200, -200, -198, -198 );
6387 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6388 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6389
6390 flush_sequence();
6391 SetRectRgn( hrgn, -4, -4, -2, -2 );
6392 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6393 SetRectRgn( hrgn, -4, -4, -3, -3 );
6394 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6395 SetRectRgn( hrgn, 0, 0, 1, 1 );
6396 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6397 ok_sequence( WmPaint, "Paint", FALSE );
6398
6399 flush_sequence();
6400 SetRectRgn( hrgn, -4, -4, -1, -1 );
6401 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6402 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6403 /* make sure no WM_PAINT was generated */
6404 flush_events();
6405 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6406
6407 flush_sequence();
6408 SetRectRgn( hrgn, -4, -4, -1, -1 );
6409 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6410 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
6411 {
6412 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6413 {
6414 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6415 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6416 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6417 ret = GetUpdateRect( hwnd, &rect, FALSE );
6418 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6419 /* this will send WM_NCPAINT and validate the non client area */
6420 ret = GetUpdateRect( hwnd, &rect, TRUE );
6421 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6422 }
6423 DispatchMessageA( &msg );
6424 }
6425 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6426
6427 DestroyWindow( hwnd );
6428
6429 /* now test with a child window */
6430
6431 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6432 100, 100, 200, 200, 0, 0, 0, NULL);
6433 ok (hparent != 0, "Failed to create parent window\n");
6434
6435 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6436 10, 10, 100, 100, hparent, 0, 0, NULL);
6437 ok (hchild != 0, "Failed to create child window\n");
6438
6439 ShowWindow( hparent, SW_SHOW );
6440 UpdateWindow( hparent );
6441 UpdateWindow( hchild );
6442 flush_events();
6443 flush_sequence();
6444 log_all_parent_messages++;
6445
6446 SetRect( &rect, 0, 0, 50, 50 );
6447 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6448 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6449 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6450
6451 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6452 pt.x = pt.y = 0;
6453 MapWindowPoints( hchild, hparent, &pt, 1 );
6454 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6455 check_update_rgn( hchild, hrgn );
6456 SetRectRgn( hrgn, 0, 0, 50, 50 );
6457 check_update_rgn( hparent, hrgn );
6458 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6459 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6460 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6461 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6462
6463 flush_events();
6464 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6465
6466 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6467 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6468 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6469 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6470 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6471
6472 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6473 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6474 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6475
6476 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6477 flush_sequence();
6478 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6479 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6480 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6481
6482 /* flush all paint messages */
6483 flush_events();
6484 flush_sequence();
6485
6486 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6487 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6488 SetRectRgn( hrgn, 0, 0, 50, 50 );
6489 check_update_rgn( hparent, hrgn );
6490 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6491 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6492 SetRectRgn( hrgn, 0, 0, 50, 50 );
6493 check_update_rgn( hparent, hrgn );
6494
6495 /* flush all paint messages */
6496 flush_events();
6497 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6498 flush_sequence();
6499
6500 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6501 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6502 SetRectRgn( hrgn, 0, 0, 50, 50 );
6503 check_update_rgn( hparent, hrgn );
6504 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6505 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6506 SetRectRgn( hrgn2, 10, 10, 50, 50 );
6507 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6508 check_update_rgn( hparent, hrgn );
6509 /* flush all paint messages */
6510 flush_events();
6511 flush_sequence();
6512
6513 /* same as above but parent gets completely validated */
6514 SetRect( &rect, 20, 20, 30, 30 );
6515 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6516 SetRectRgn( hrgn, 20, 20, 30, 30 );
6517 check_update_rgn( hparent, hrgn );
6518 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6519 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6520 check_update_rgn( hparent, 0 ); /* no update region */
6521 flush_events();
6522 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
6523
6524 /* make sure RDW_VALIDATE on child doesn't have the same effect */
6525 flush_sequence();
6526 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6527 SetRectRgn( hrgn, 20, 20, 30, 30 );
6528 check_update_rgn( hparent, hrgn );
6529 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6530 SetRectRgn( hrgn, 20, 20, 30, 30 );
6531 check_update_rgn( hparent, hrgn );
6532
6533 /* same as above but normal WM_PAINT doesn't validate parent */
6534 flush_sequence();
6535 SetRect( &rect, 20, 20, 30, 30 );
6536 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6537 SetRectRgn( hrgn, 20, 20, 30, 30 );
6538 check_update_rgn( hparent, hrgn );
6539 /* no WM_PAINT in child while parent still pending */
6540 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6541 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6542 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6543 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6544
6545 flush_sequence();
6546 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6547 /* no WM_PAINT in child while parent still pending */
6548 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6549 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6550 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6551 /* now that parent is valid child should get WM_PAINT */
6552 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6553 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6554 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6555 ok_sequence( WmEmptySeq, "No other message", FALSE );
6556
6557 /* same thing with WS_CLIPCHILDREN in parent */
6558 flush_sequence();
6559 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6560 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6561 /* changing style invalidates non client area, but we need to invalidate something else to see it */
6562 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6563 ok_sequence( WmEmptySeq, "No message", FALSE );
6564 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6565 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6566
6567 flush_sequence();
6568 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6569 SetRectRgn( hrgn, 20, 20, 30, 30 );
6570 check_update_rgn( hparent, hrgn );
6571 /* no WM_PAINT in child while parent still pending */
6572 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6573 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6574 /* WM_PAINT in parent first */
6575 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6576 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6577
6578 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6579 flush_sequence();
6580 SetRect( &rect, 0, 0, 30, 30 );
6581 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6582 SetRectRgn( hrgn, 0, 0, 30, 30 );
6583 check_update_rgn( hparent, hrgn );
6584 flush_events();
6585 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6586
6587 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6588 flush_sequence();
6589 SetRect( &rect, -10, 0, 30, 30 );
6590 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6591 SetRect( &rect, 0, 0, 20, 20 );
6592 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6593 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6594 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6595
6596 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6597 flush_sequence();
6598 SetRect( &rect, -10, 0, 30, 30 );
6599 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6600 SetRect( &rect, 0, 0, 100, 100 );
6601 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6602 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6603 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6604 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6605 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6606
6607 /* test RDW_INTERNALPAINT behavior */
6608
6609 flush_sequence();
6610 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6611 flush_events();
6612 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6613
6614 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6615 flush_events();
6616 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6617
6618 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6619 flush_events();
6620 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6621
6622 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6623 UpdateWindow( hparent );
6624 flush_events();
6625 flush_sequence();
6626 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6627 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6628 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6629 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6630 flush_events();
6631 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6632
6633 UpdateWindow( hparent );
6634 flush_events();
6635 flush_sequence();
6636 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6637 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6638 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6639 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6640 flush_events();
6641 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6642
6643 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6644 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6645 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6646 flush_events();
6647 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6648
6649 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6650 UpdateWindow( hparent );
6651 flush_events();
6652 flush_sequence();
6653 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6654 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6655 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6656 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6657 flush_events();
6658 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6659
6660 UpdateWindow( hparent );
6661 flush_events();
6662 flush_sequence();
6663 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6664 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6665 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6666 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6667 flush_events();
6668 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6669
6670 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6671 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6672
6673 UpdateWindow( hparent );
6674 flush_events();
6675 flush_sequence();
6676 trace("testing SetWindowPos(-10000, -10000) on child\n");
6677 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6678 check_update_rgn( hchild, 0 );
6679 flush_events();
6680
6681 #if 0 /* this one doesn't pass under Wine yet */
6682 UpdateWindow( hparent );
6683 flush_events();
6684 flush_sequence();
6685 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6686 ShowWindow( hchild, SW_MINIMIZE );
6687 check_update_rgn( hchild, 0 );
6688 flush_events();
6689 #endif
6690
6691 UpdateWindow( hparent );
6692 flush_events();
6693 flush_sequence();
6694 trace("testing SetWindowPos(-10000, -10000) on parent\n");
6695 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6696 check_update_rgn( hparent, 0 );
6697 flush_events();
6698
6699 log_all_parent_messages--;
6700 DestroyWindow( hparent );
6701 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6702
6703 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6704
6705 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6706 100, 100, 200, 200, 0, 0, 0, NULL);
6707 ok (hparent != 0, "Failed to create parent window\n");
6708
6709 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6710 10, 10, 100, 100, hparent, 0, 0, NULL);
6711 ok (hchild != 0, "Failed to create child window\n");
6712
6713 ShowWindow( hparent, SW_SHOW );
6714 UpdateWindow( hparent );
6715 UpdateWindow( hchild );
6716 flush_events();
6717 flush_sequence();
6718
6719 /* moving child outside of parent boundaries changes update region */
6720 SetRect( &rect, 0, 0, 40, 40 );
6721 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6722 SetRectRgn( hrgn, 0, 0, 40, 40 );
6723 check_update_rgn( hchild, hrgn );
6724 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6725 SetRectRgn( hrgn, 10, 0, 40, 40 );
6726 check_update_rgn( hchild, hrgn );
6727 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6728 SetRectRgn( hrgn, 10, 10, 40, 40 );
6729 check_update_rgn( hchild, hrgn );
6730
6731 /* moving parent off-screen does too */
6732 SetRect( &rect, 0, 0, 100, 100 );
6733 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6734 SetRectRgn( hrgn, 0, 0, 100, 100 );
6735 check_update_rgn( hparent, hrgn );
6736 SetRectRgn( hrgn, 10, 10, 40, 40 );
6737 check_update_rgn( hchild, hrgn );
6738 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6739 SetRectRgn( hrgn, 20, 20, 100, 100 );
6740 check_update_rgn( hparent, hrgn );
6741 SetRectRgn( hrgn, 30, 30, 40, 40 );
6742 check_update_rgn( hchild, hrgn );
6743
6744 /* invalidated region is cropped by the parent rects */
6745 SetRect( &rect, 0, 0, 50, 50 );
6746 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6747 SetRectRgn( hrgn, 30, 30, 50, 50 );
6748 check_update_rgn( hchild, hrgn );
6749
6750 DestroyWindow( hparent );
6751 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6752 flush_sequence();
6753
6754 DeleteObject( hrgn );
6755 DeleteObject( hrgn2 );
6756 }
6757
6758 struct wnd_event
6759 {
6760 HWND hwnd;
6761 HANDLE grand_child;
6762 HANDLE start_event;
6763 HANDLE stop_event;
6764 };
6765
6766 static DWORD WINAPI thread_proc(void *param)
6767 {
6768 MSG msg;
6769 struct wnd_event *wnd_event = param;
6770
6771 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6772 100, 100, 200, 200, 0, 0, 0, NULL);
6773 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6774
6775 SetEvent(wnd_event->start_event);
6776
6777 while (GetMessageA(&msg, 0, 0, 0))
6778 {
6779 TranslateMessage(&msg);
6780 DispatchMessageA(&msg);
6781 }
6782
6783 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6784
6785 return 0;
6786 }
6787
6788 static DWORD CALLBACK create_grand_child_thread( void *param )
6789 {
6790 struct wnd_event *wnd_event = param;
6791 HWND hchild;
6792 MSG msg;
6793
6794 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6795 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6796 ok (hchild != 0, "Failed to create child window\n");
6797 flush_events();
6798 flush_sequence();
6799 SetEvent( wnd_event->start_event );
6800
6801 for (;;)
6802 {
6803 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6804 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
6805 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6806 }
6807 return 0;
6808 }
6809
6810 static DWORD CALLBACK create_child_thread( void *param )
6811 {
6812 struct wnd_event *wnd_event = param;
6813 struct wnd_event child_event;
6814 DWORD ret, tid;
6815 MSG msg;
6816
6817 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6818 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6819 ok (child_event.hwnd != 0, "Failed to create child window\n");
6820 SetFocus( child_event.hwnd );
6821 flush_events();
6822 flush_sequence();
6823 child_event.start_event = wnd_event->start_event;
6824 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6825 for (;;)
6826 {
6827 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6828 if (ret != 1) break;
6829 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6830 }
6831 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6832 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6833 return 0;
6834 }
6835
6836 static const char manifest_dep[] =
6837 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
6838 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
6839 " <file name=\"testdep.dll\" />"
6840 "</assembly>";
6841
6842 static const char manifest_main[] =
6843 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
6844 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
6845 "<dependency>"
6846 " <dependentAssembly>"
6847 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
6848 " </dependentAssembly>"
6849 "</dependency>"
6850 "</assembly>";
6851
6852 static void create_manifest_file(const char *filename, const char *manifest)
6853 {
6854 WCHAR path[MAX_PATH];
6855 HANDLE file;
6856 DWORD size;
6857
6858 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
6859 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6860 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
6861 WriteFile(file, manifest, strlen(manifest), &size, NULL);
6862 CloseHandle(file);
6863 }
6864
6865 static HANDLE test_create(const char *file)
6866 {
6867 WCHAR path[MAX_PATH];
6868 ACTCTXW actctx;
6869 HANDLE handle;
6870
6871 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
6872 memset(&actctx, 0, sizeof(ACTCTXW));
6873 actctx.cbSize = sizeof(ACTCTXW);
6874 actctx.lpSource = path;
6875
6876 handle = pCreateActCtxW(&actctx);
6877 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
6878
6879 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
6880 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
6881 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
6882 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
6883 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
6884 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
6885 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
6886 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
6887 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
6888
6889 return handle;
6890 }
6891
6892 static void test_interthread_messages(void)
6893 {
6894 HANDLE hThread, context, handle, event;
6895 ULONG_PTR cookie;
6896 DWORD tid;
6897 WNDPROC proc;
6898 MSG msg;
6899 char buf[256];
6900 int len, expected_len;
6901 struct wnd_event wnd_event;
6902 BOOL ret;
6903
6904 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6905 if (!wnd_event.start_event)
6906 {
6907 win_skip("skipping interthread message test under win9x\n");
6908 return;
6909 }
6910
6911 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6912 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6913
6914 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6915
6916 CloseHandle(wnd_event.start_event);
6917
6918 SetLastError(0xdeadbeef);
6919 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
6920 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6921 "wrong error code %d\n", GetLastError());
6922
6923 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6924 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6925
6926 expected_len = lstrlenA("window caption text");
6927 memset(buf, 0, sizeof(buf));
6928 SetLastError(0xdeadbeef);
6929 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6930 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6931 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6932
6933 msg.hwnd = wnd_event.hwnd;
6934 msg.message = WM_GETTEXT;
6935 msg.wParam = sizeof(buf);
6936 msg.lParam = (LPARAM)buf;
6937 memset(buf, 0, sizeof(buf));
6938 SetLastError(0xdeadbeef);
6939 len = DispatchMessageA(&msg);
6940 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6941 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
6942
6943 /* the following test causes an exception in user.exe under win9x */
6944 msg.hwnd = wnd_event.hwnd;
6945 msg.message = WM_TIMER;
6946 msg.wParam = 0;
6947 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6948 SetLastError(0xdeadbeef);
6949 len = DispatchMessageA(&msg);
6950 ok(!len && GetLastError() == 0xdeadbeef,
6951 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6952
6953 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6954 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6955
6956 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6957 CloseHandle(hThread);
6958
6959 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6960
6961 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6962 100, 100, 200, 200, 0, 0, 0, NULL);
6963 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6964 flush_events();
6965 flush_sequence();
6966 log_all_parent_messages++;
6967 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6968 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6969 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6970 for (;;)
6971 {
6972 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6973 if (ret != 1) break;
6974 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6975 }
6976 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6977 /* now wait for the thread without processing messages; this shouldn't deadlock */
6978 SetEvent( wnd_event.stop_event );
6979 ret = WaitForSingleObject( hThread, 5000 );
6980 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6981 CloseHandle( hThread );
6982
6983 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6984 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6985 CloseHandle( wnd_event.grand_child );
6986
6987 CloseHandle( wnd_event.start_event );
6988 CloseHandle( wnd_event.stop_event );
6989 flush_events();
6990 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6991 log_all_parent_messages--;
6992 DestroyWindow( wnd_event.hwnd );
6993
6994 /* activation context tests */
6995 if (!pActivateActCtx)
6996 {
6997 win_skip("Activation contexts are not supported, skipping\n");
6998 return;
6999 }
7000
7001 create_manifest_file("testdep1.manifest", manifest_dep);
7002 create_manifest_file("main.manifest", manifest_main);
7003
7004 context = test_create("main.manifest");
7005 DeleteFileA("testdep1.manifest");
7006 DeleteFileA("main.manifest");
7007
7008 handle = (void*)0xdeadbeef;
7009 ret = pGetCurrentActCtx(&handle);
7010 ok(ret, "GetCurentActCtx failed: %u\n", GetLastError());
7011 ok(handle == 0, "active context %p\n", handle);
7012
7013 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
7014 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
7015 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
7016 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7017 CloseHandle(wnd_event.start_event);
7018
7019 /* context is activated after thread creation, so it doesn't inherit it by default */
7020 ret = pActivateActCtx(context, &cookie);
7021 ok(ret, "activation failed: %u\n", GetLastError());
7022
7023 handle = 0;
7024 ret = pGetCurrentActCtx(&handle);
7025 ok(ret, "GetCurentActCtx failed: %u\n", GetLastError());
7026 ok(handle != 0, "active context %p\n", handle);
7027 pReleaseActCtx(handle);
7028
7029 /* destination window will test for active context */
7030 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
7031 ok(ret, "thread window returned %d\n", ret);
7032
7033 event = CreateEventW(NULL, 0, 0, NULL);
7034 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
7035 ok(ret, "thread window returned %d\n", ret);
7036 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7037 CloseHandle(event);
7038
7039 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
7040 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
7041
7042 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7043 CloseHandle(hThread);
7044
7045 ret = pDeactivateActCtx(0, cookie);
7046 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
7047 pReleaseActCtx(context);
7048 }
7049
7050
7051 static const struct message WmVkN[] = {
7052 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7053 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7054 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7055 { WM_CHAR, wparam|lparam, 'n', 1 },
7056 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
7057 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7058 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7059 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7060 { 0 }
7061 };
7062 static const struct message WmShiftVkN[] = {
7063 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7064 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7065 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7066 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7067 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7068 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7069 { WM_CHAR, wparam|lparam, 'N', 1 },
7070 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
7071 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7072 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7073 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7074 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7075 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7076 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7077 { 0 }
7078 };
7079 static const struct message WmCtrlVkN[] = {
7080 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7081 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7082 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7083 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7084 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7085 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7086 { WM_CHAR, wparam|lparam, 0x000e, 1 },
7087 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
7088 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7089 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7090 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7091 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7092 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7093 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7094 { 0 }
7095 };
7096 static const struct message WmCtrlVkN_2[] = {
7097 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7098 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7099 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7100 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7101 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7102 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
7103 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7104 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7105 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7106 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7107 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7108 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7109 { 0 }
7110 };
7111 static const struct message WmAltVkN[] = {
7112 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7113 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7114 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7115 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7116 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
7117 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
7118 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
7119 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
7120 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
7121 { HCBT_SYSCOMMAND, hook },
7122 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7123 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7124 { 0x00AE, sent|defwinproc|optional }, /* XP */
7125 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
7126 { WM_INITMENU, sent|defwinproc },
7127 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7128 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
7129 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7130 { WM_CAPTURECHANGED, sent|defwinproc },
7131 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
7132 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7133 { WM_EXITMENULOOP, sent|defwinproc },
7134 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
7135 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
7136 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7137 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
7138 { WM_SYSKEYUP, 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 { 0 }
7143 };
7144 static const struct message WmAltVkN_2[] = {
7145 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7146 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7147 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7148 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7149 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
7150 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
7151 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7152 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
7153 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7154 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7155 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7156 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7157 { 0 }
7158 };
7159 static const struct message WmCtrlAltVkN[] = {
7160 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7161 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7162 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7163 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7164 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7165 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7166 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7167 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
7168 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
7169 { WM_CHAR, optional },
7170 { WM_CHAR, sent|optional },
7171 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7172 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
7173 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7174 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7175 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7176 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7177 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7178 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7179 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7180 { 0 }
7181 };
7182 static const struct message WmCtrlShiftVkN[] = {
7183 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7184 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7185 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7186 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7187 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7188 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7189 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7190 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7191 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
7192 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7193 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7194 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7195 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7196 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7197 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7198 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7199 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7200 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7201 { 0 }
7202 };
7203 static const struct message WmCtrlAltShiftVkN[] = {
7204 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7205 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7206 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7207 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7208 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7209 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7210 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
7211 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
7212 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
7213 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7214 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
7215 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
7216 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7217 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
7218 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7219 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
7220 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
7221 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
7222 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7223 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7224 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7225 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7226 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7227 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7228 { 0 }
7229 };
7230 static const struct message WmAltPressRelease[] = {
7231 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7232 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7233 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7234 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7235 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7236 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7237 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
7238 { HCBT_SYSCOMMAND, hook },
7239 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7240 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7241 { WM_INITMENU, sent|defwinproc },
7242 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7243 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7244 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7245
7246 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
7247
7248 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7249 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7250 { WM_CAPTURECHANGED, sent|defwinproc },
7251 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7252 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7253 { WM_EXITMENULOOP, sent|defwinproc },
7254 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7255 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7256 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7257 { 0 }
7258 };
7259 static const struct message WmShiftMouseButton[] = {
7260 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7261 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7262 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7263 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
7264 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
7265 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
7266 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
7267 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
7268 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
7269 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7270 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7271 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7272 { 0 }
7273 };
7274 static const struct message WmF1Seq[] = {
7275 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
7276 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
7277 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
7278 { WM_KEYF1, wparam|lparam, 0, 0 },
7279 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
7280 { WM_HELP, sent|defwinproc },
7281 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
7282 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
7283 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
7284 { 0 }
7285 };
7286 static const struct message WmVkAppsSeq[] = {
7287 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
7288 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
7289 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
7290 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
7291 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
7292 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
7293 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
7294 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
7295 { 0 }
7296 };
7297 static const struct message WmVkF10Seq[] = {
7298 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7299 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7300 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7301 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7302 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7303 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7304 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7305 { HCBT_SYSCOMMAND, hook },
7306 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7307 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7308 { WM_INITMENU, sent|defwinproc },
7309 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7310 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7311 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7312
7313 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
7314
7315 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7316 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7317 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7318 { WM_CAPTURECHANGED, sent|defwinproc },
7319 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7320 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7321 { WM_EXITMENULOOP, sent|defwinproc },
7322 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7323 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7324 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7325 { 0 }
7326 };
7327 static const struct message WmShiftF10Seq[] = {
7328 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7329 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7330 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
7331 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7332 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7333 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7334 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
7335 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7336 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7337 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7338 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7339 { HCBT_SYSCOMMAND, hook },
7340 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7341 { WM_INITMENU, sent|defwinproc },
7342 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7343 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
7344 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
7345 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
7346 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
7347 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7348 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
7349 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
7350 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
7351 { 0 }
7352 };
7353
7354 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
7355 {
7356 MSG msg;
7357
7358 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
7359 {
7360 struct recvd_message log_msg;
7361
7362 /* ignore some unwanted messages */
7363 if (msg.message == WM_MOUSEMOVE ||
7364 msg.message == WM_TIMER ||
7365 ignore_message( msg.message ))
7366 continue;
7367
7368 log_msg.hwnd = msg.hwnd;
7369 log_msg.message = msg.message;
7370 log_msg.flags = wparam|lparam;
7371 log_msg.wParam = msg.wParam;
7372 log_msg.lParam = msg.lParam;
7373 log_msg.descr = "accel";
7374 add_message(&log_msg);
7375
7376 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
7377 {
7378 TranslateMessage(&msg);
7379 DispatchMessageA(&msg);
7380 }
7381 }
7382 }
7383
7384 static void test_accelerators(void)
7385 {
7386 RECT rc;
7387 POINT pt;
7388 SHORT state;
7389 HACCEL hAccel;
7390 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7391 100, 100, 200, 200, 0, 0, 0, NULL);
7392 BOOL ret;
7393
7394 assert(hwnd != 0);
7395 UpdateWindow(hwnd);
7396 flush_events();
7397 flush_sequence();
7398
7399 SetFocus(hwnd);
7400 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
7401
7402 state = GetKeyState(VK_SHIFT);
7403 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
7404 state = GetKeyState(VK_CAPITAL);
7405 ok(state == 0, "wrong CapsLock state %04x\n", state);
7406
7407 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
7408 assert(hAccel != 0);
7409
7410 flush_events();
7411 pump_msg_loop(hwnd, 0);
7412 flush_sequence();
7413
7414 trace("testing VK_N press/release\n");
7415 flush_sequence();
7416 keybd_event('N', 0, 0, 0);
7417 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7418 pump_msg_loop(hwnd, hAccel);
7419 if (!sequence_cnt) /* we didn't get any message */
7420 {
7421 skip( "queuing key events not supported\n" );
7422 goto done;
7423 }
7424 ok_sequence(WmVkN, "VK_N press/release", FALSE);
7425
7426 trace("testing Shift+VK_N press/release\n");
7427 flush_sequence();
7428 keybd_event(VK_SHIFT, 0, 0, 0);
7429 keybd_event('N', 0, 0, 0);
7430 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7431 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7432 pump_msg_loop(hwnd, hAccel);
7433 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7434
7435 trace("testing Ctrl+VK_N press/release\n");
7436 flush_sequence();
7437 keybd_event(VK_CONTROL, 0, 0, 0);
7438 keybd_event('N', 0, 0, 0);
7439 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7440 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7441 pump_msg_loop(hwnd, hAccel);
7442 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
7443
7444 trace("testing Alt+VK_N press/release\n");
7445 flush_sequence();
7446 keybd_event(VK_MENU, 0, 0, 0);
7447 keybd_event('N', 0, 0, 0);
7448 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7449 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7450 pump_msg_loop(hwnd, hAccel);
7451 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
7452
7453 trace("testing Ctrl+Alt+VK_N press/release 1\n");
7454 flush_sequence();
7455 keybd_event(VK_CONTROL, 0, 0, 0);
7456 keybd_event(VK_MENU, 0, 0, 0);
7457 keybd_event('N', 0, 0, 0);
7458 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7459 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7460 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7461 pump_msg_loop(hwnd, hAccel);
7462 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
7463
7464 ret = DestroyAcceleratorTable(hAccel);
7465 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7466
7467 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
7468 assert(hAccel != 0);
7469
7470 trace("testing VK_N press/release\n");
7471 flush_sequence();
7472 keybd_event('N', 0, 0, 0);
7473 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7474 pump_msg_loop(hwnd, hAccel);
7475 ok_sequence(WmVkN, "VK_N press/release", FALSE);
7476
7477 trace("testing Shift+VK_N press/release\n");
7478 flush_sequence();
7479 keybd_event(VK_SHIFT, 0, 0, 0);
7480 keybd_event('N', 0, 0, 0);
7481 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7482 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7483 pump_msg_loop(hwnd, hAccel);
7484 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7485
7486 trace("testing Ctrl+VK_N press/release 2\n");
7487 flush_sequence();
7488 keybd_event(VK_CONTROL, 0, 0, 0);
7489 keybd_event('N', 0, 0, 0);
7490 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7491 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7492 pump_msg_loop(hwnd, hAccel);
7493 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7494
7495 trace("testing Alt+VK_N press/release 2\n");
7496 flush_sequence();
7497 keybd_event(VK_MENU, 0, 0, 0);
7498 keybd_event('N', 0, 0, 0);
7499 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7500 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7501 pump_msg_loop(hwnd, hAccel);
7502 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7503
7504 trace("testing Ctrl+Alt+VK_N press/release 2\n");
7505 flush_sequence();
7506 keybd_event(VK_CONTROL, 0, 0, 0);
7507 keybd_event(VK_MENU, 0, 0, 0);
7508 keybd_event('N', 0, 0, 0);
7509 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7510 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7511 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7512 pump_msg_loop(hwnd, hAccel);
7513 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7514
7515 trace("testing Ctrl+Shift+VK_N press/release\n");
7516 flush_sequence();
7517 keybd_event(VK_CONTROL, 0, 0, 0);
7518 keybd_event(VK_SHIFT, 0, 0, 0);
7519 keybd_event('N', 0, 0, 0);
7520 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7521 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7522 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7523 pump_msg_loop(hwnd, hAccel);
7524 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7525
7526 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7527 flush_sequence();
7528 keybd_event(VK_CONTROL, 0, 0, 0);
7529 keybd_event(VK_MENU, 0, 0, 0);
7530 keybd_event(VK_SHIFT, 0, 0, 0);
7531 keybd_event('N', 0, 0, 0);
7532 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7533 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7534 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7535 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7536 pump_msg_loop(hwnd, hAccel);
7537 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7538
7539 ret = DestroyAcceleratorTable(hAccel);
7540 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7541 hAccel = 0;
7542
7543 trace("testing Alt press/release\n");
7544 flush_sequence();
7545 keybd_event(VK_MENU, 0, 0, 0);
7546 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7547 keybd_event(VK_MENU, 0, 0, 0);
7548 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7549 pump_msg_loop(hwnd, 0);
7550 /* this test doesn't pass in Wine for managed windows */
7551 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7552
7553 trace("testing VK_F1 press/release\n");
7554 keybd_event(VK_F1, 0, 0, 0);
7555 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7556 pump_msg_loop(hwnd, 0);
7557 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7558
7559 trace("testing VK_APPS press/release\n");
7560 keybd_event(VK_APPS, 0, 0, 0);
7561 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7562 pump_msg_loop(hwnd, 0);
7563 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7564
7565 trace("testing VK_F10 press/release\n");
7566 keybd_event(VK_F10, 0, 0, 0);
7567 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7568 keybd_event(VK_F10, 0, 0, 0);
7569 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7570 pump_msg_loop(hwnd, 0);
7571 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
7572
7573 trace("testing SHIFT+F10 press/release\n");
7574 keybd_event(VK_SHIFT, 0, 0, 0);
7575 keybd_event(VK_F10, 0, 0, 0);
7576 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7577 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7578 keybd_event(VK_ESCAPE, 0, 0, 0);
7579 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
7580 pump_msg_loop(hwnd, 0);
7581 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
7582
7583 trace("testing Shift+MouseButton press/release\n");
7584 /* first, move mouse pointer inside of the window client area */
7585 GetClientRect(hwnd, &rc);
7586 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7587 rc.left += (rc.right - rc.left)/2;
7588 rc.top += (rc.bottom - rc.top)/2;
7589 SetCursorPos(rc.left, rc.top);
7590 SetActiveWindow(hwnd);
7591
7592 flush_events();
7593 flush_sequence();
7594 GetCursorPos(&pt);
7595 if (pt.x == rc.left && pt.y == rc.top)
7596 {
7597 int i;
7598 keybd_event(VK_SHIFT, 0, 0, 0);
7599 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7600 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7601 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7602 pump_msg_loop(hwnd, 0);
7603 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7604 if (i < sequence_cnt)
7605 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7606 else
7607 skip( "Shift+MouseButton event didn't get to the window\n" );
7608 }
7609
7610 done:
7611 if (hAccel) DestroyAcceleratorTable(hAccel);
7612 DestroyWindow(hwnd);
7613 }
7614
7615 /************* window procedures ********************/
7616
7617 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
7618 WPARAM wParam, LPARAM lParam)
7619 {
7620 static LONG defwndproc_counter = 0;
7621 static LONG beginpaint_counter = 0;
7622 LRESULT ret;
7623 struct recvd_message msg;
7624
7625 if (ignore_message( message )) return 0;
7626
7627 switch (message)
7628 {
7629 case WM_ENABLE:
7630 {
7631 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7632 ok((BOOL)wParam == !(style & WS_DISABLED),
7633 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7634 break;
7635 }
7636
7637 case WM_CAPTURECHANGED:
7638 if (test_DestroyWindow_flag)
7639 {
7640 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7641 if (style & WS_CHILD)
7642 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7643 else if (style & WS_POPUP)
7644 lParam = WND_POPUP_ID;
7645 else
7646 lParam = WND_PARENT_ID;
7647 }
7648 break;
7649
7650 case WM_NCDESTROY:
7651 {
7652 HWND capture;
7653
7654 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7655 capture = GetCapture();
7656 if (capture)
7657 {
7658 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7659 trace("current capture %p, releasing...\n", capture);
7660 ReleaseCapture();
7661 }
7662 }
7663 /* fall through */
7664 case WM_DESTROY:
7665 if (pGetAncestor)
7666 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7667 if (test_DestroyWindow_flag)
7668 {
7669 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7670 if (style & WS_CHILD)
7671 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7672 else if (style & WS_POPUP)
7673 lParam = WND_POPUP_ID;
7674 else
7675 lParam = WND_PARENT_ID;
7676 }
7677 break;
7678
7679 /* test_accelerators() depends on this */
7680 case WM_NCHITTEST:
7681 return HTCLIENT;
7682
7683 case WM_USER+10:
7684 {
7685 HANDLE handle, event = (HANDLE)lParam;
7686 BOOL ret;
7687
7688 handle = (void*)0xdeadbeef;
7689 ret = pGetCurrentActCtx(&handle);
7690 ok(ret, "failed to get current context, %u\n", GetLastError());
7691 ok(handle == 0, "got active context %p\n", handle);
7692 if (event) SetEvent(event);
7693 return 1;
7694 }
7695
7696 /* ignore */
7697 case WM_MOUSEMOVE:
7698 case WM_MOUSEACTIVATE:
7699 case WM_NCMOUSEMOVE:
7700 case WM_SETCURSOR:
7701 case WM_IME_SELECT:
7702 return 0;
7703 }
7704
7705 msg.hwnd = hwnd;
7706 msg.message = message;
7707 msg.flags = sent|wparam|lparam;
7708 if (defwndproc_counter) msg.flags |= defwinproc;
7709 if (beginpaint_counter) msg.flags |= beginpaint;
7710 msg.wParam = wParam;
7711 msg.lParam = lParam;
7712 msg.descr = "MsgCheckProc";
7713 add_message(&msg);
7714
7715 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7716 {
7717 HWND parent = GetParent(hwnd);
7718 RECT rc;
7719 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7720
7721 GetClientRect(parent, &rc);
7722 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7723 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7724 minmax->ptReserved.x, minmax->ptReserved.y,
7725 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7726 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7727 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7728 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7729
7730 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7731 minmax->ptMaxSize.x, rc.right);
7732 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7733 minmax->ptMaxSize.y, rc.bottom);
7734 }
7735
7736 if (message == WM_PAINT)
7737 {
7738 PAINTSTRUCT ps;
7739 beginpaint_counter++;
7740 BeginPaint( hwnd, &ps );
7741 beginpaint_counter--;
7742 EndPaint( hwnd, &ps );
7743 return 0;
7744 }
7745
7746 defwndproc_counter++;
7747 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
7748 : DefWindowProcA(hwnd, message, wParam, lParam);
7749 defwndproc_counter--;
7750
7751 return ret;
7752 }
7753
7754 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7755 {
7756 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7757 }
7758
7759 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7760 {
7761 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7762 }
7763
7764 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7765 {
7766 static LONG defwndproc_counter = 0;
7767 LRESULT ret;
7768 struct recvd_message msg;
7769
7770 if (ignore_message( message )) return 0;
7771
7772 switch (message)
7773 {
7774 case WM_QUERYENDSESSION:
7775 case WM_ENDSESSION:
7776 lParam &= ~0x01; /* Vista adds a 0x01 flag */
7777 break;
7778 }
7779
7780 msg.hwnd = hwnd;
7781 msg.message = message;
7782 msg.flags = sent|wparam|lparam;
7783 if (defwndproc_counter) msg.flags |= defwinproc;
7784 msg.wParam = wParam;
7785 msg.lParam = lParam;
7786 msg.descr = "popup";
7787 add_message(&msg);
7788
7789 if (message == WM_CREATE)
7790 {
7791 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7792 SetWindowLongA(hwnd, GWL_STYLE, style);
7793 }
7794
7795 defwndproc_counter++;
7796 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7797 defwndproc_counter--;
7798
7799 return ret;
7800 }
7801
7802 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7803 {
7804 static LONG defwndproc_counter = 0;
7805 static LONG beginpaint_counter = 0;
7806 LRESULT ret;
7807 struct recvd_message msg;
7808
7809 if (ignore_message( message )) return 0;
7810
7811 if (log_all_parent_messages ||
7812 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7813 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7814 message == WM_ENABLE || message == WM_ENTERIDLE ||
7815 message == WM_DRAWITEM || message == WM_COMMAND ||
7816 message == WM_IME_SETCONTEXT)
7817 {
7818 switch (message)
7819 {
7820 /* ignore */
7821 case WM_NCHITTEST:
7822 return HTCLIENT;
7823 case WM_SETCURSOR:
7824 case WM_MOUSEMOVE:
7825 case WM_NCMOUSEMOVE:
7826 return 0;
7827
7828 case WM_ERASEBKGND:
7829 {
7830 RECT rc;
7831 INT ret = GetClipBox((HDC)wParam, &rc);
7832
7833 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7834 ret, rc.left, rc.top, rc.right, rc.bottom);
7835 break;
7836 }
7837 }
7838
7839 msg.hwnd = hwnd;
7840 msg.message = message;
7841 msg.flags = sent|parent|wparam|lparam;
7842 if (defwndproc_counter) msg.flags |= defwinproc;
7843 if (beginpaint_counter) msg.flags |= beginpaint;
7844 msg.wParam = wParam;
7845 msg.lParam = lParam;
7846 msg.descr = "parent";
7847 add_message(&msg);
7848 }
7849
7850 if (message == WM_PAINT)
7851 {
7852 PAINTSTRUCT ps;
7853 beginpaint_counter++;
7854 BeginPaint( hwnd, &ps );
7855 beginpaint_counter--;
7856 EndPaint( hwnd, &ps );
7857 return 0;
7858 }
7859
7860 defwndproc_counter++;
7861 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7862 defwndproc_counter--;
7863
7864 return ret;
7865 }
7866
7867 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
7868 {
7869 if (message == WM_CREATE)
7870 PostMessageA(hwnd, WM_CLOSE, 0, 0);
7871 else if (message == WM_CLOSE)
7872 {
7873 /* Only the first WM_QUIT will survive the window destruction */
7874 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
7875 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
7876 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
7877 }
7878
7879 return DefWindowProcA(hwnd, message, wp, lp);
7880 }
7881
7882 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7883 {
7884 static LONG defwndproc_counter = 0;
7885 LRESULT ret;
7886 struct recvd_message msg;
7887
7888 if (ignore_message( message )) return 0;
7889
7890 if (test_def_id)
7891 {
7892 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7893 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7894 if (after_end_dialog)
7895 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7896 else
7897 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7898 }
7899
7900 msg.hwnd = hwnd;
7901 msg.message = message;
7902 msg.flags = sent|wparam|lparam;
7903 if (defwndproc_counter) msg.flags |= defwinproc;
7904 msg.wParam = wParam;
7905 msg.lParam = lParam;
7906 msg.descr = "dialog";
7907 add_message(&msg);
7908
7909 defwndproc_counter++;
7910 ret = DefDlgProcA(hwnd, message, wParam, lParam);
7911 defwndproc_counter--;
7912
7913 return ret;
7914 }
7915
7916 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7917 {
7918 static LONG defwndproc_counter = 0;
7919 LRESULT ret;
7920 struct recvd_message msg;
7921
7922 /* log only specific messages we are interested in */
7923 switch (message)
7924 {
7925 #if 0 /* probably log these as well */
7926 case WM_ACTIVATE:
7927 case WM_SETFOCUS:
7928 case WM_KILLFOCUS:
7929 #endif
7930 case WM_SHOWWINDOW:
7931 case WM_SIZE:
7932 case WM_MOVE:
7933 case WM_GETMINMAXINFO:
7934 case WM_WINDOWPOSCHANGING:
7935 case WM_WINDOWPOSCHANGED:
7936 break;
7937
7938 default: /* ignore */
7939 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7940 return DefWindowProcA(hwnd, message, wParam, lParam);
7941 }
7942
7943 msg.hwnd = hwnd;
7944 msg.message = message;
7945 msg.flags = sent|wparam|lparam;
7946 if (defwndproc_counter) msg.flags |= defwinproc;
7947 msg.wParam = wParam;
7948 msg.lParam = lParam;
7949 msg.descr = "show";
7950 add_message(&msg);
7951
7952 defwndproc_counter++;
7953 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7954 defwndproc_counter--;
7955
7956 return ret;
7957 }
7958
7959 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7960 {
7961 switch (msg)
7962 {
7963 case WM_CREATE: return 0;
7964 case WM_PAINT:
7965 {
7966 MSG msg2;
7967 static int i = 0;
7968
7969 if (i < 256)
7970 {
7971 i++;
7972 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7973 {
7974 TranslateMessage(&msg2);
7975 DispatchMessageA(&msg2);
7976 }
7977 i--;
7978 }
7979 else ok(broken(1), "infinite loop\n");
7980 if ( i == 0)
7981 paint_loop_done = TRUE;
7982 return DefWindowProcA(hWnd,msg,wParam,lParam);
7983 }
7984 }
7985 return DefWindowProcA(hWnd,msg,wParam,lParam);
7986 }
7987
7988 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7989 {
7990 static LONG defwndproc_counter = 0;
7991 LRESULT ret;
7992 struct recvd_message msg;
7993 DWORD queue_status;
7994
7995 if (ignore_message( message )) return 0;
7996
7997 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
7998 message == WM_HOTKEY || message >= WM_APP)
7999 {
8000 msg.hwnd = hwnd;
8001 msg.message = message;
8002 msg.flags = sent|wparam|lparam;
8003 if (defwndproc_counter) msg.flags |= defwinproc;
8004 msg.wParam = wParam;
8005 msg.lParam = lParam;
8006 msg.descr = "HotkeyMsgCheckProcA";
8007 add_message(&msg);
8008 }
8009
8010 defwndproc_counter++;
8011 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8012 defwndproc_counter--;
8013
8014 if (message == WM_APP)
8015 {
8016 queue_status = GetQueueStatus(QS_HOTKEY);
8017 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
8018 queue_status = GetQueueStatus(QS_POSTMESSAGE);
8019 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
8020 PostMessageA(hwnd, WM_APP+1, 0, 0);
8021 }
8022 else if (message == WM_APP+1)
8023 {
8024 queue_status = GetQueueStatus(QS_HOTKEY);
8025 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
8026 }
8027
8028 return ret;
8029 }
8030
8031 static BOOL RegisterWindowClasses(void)
8032 {
8033 WNDCLASSA cls;
8034 WNDCLASSW clsW;
8035
8036 cls.style = 0;
8037 cls.lpfnWndProc = MsgCheckProcA;
8038 cls.cbClsExtra = 0;
8039 cls.cbWndExtra = 0;
8040 cls.hInstance = GetModuleHandleA(0);
8041 cls.hIcon = 0;
8042 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
8043 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
8044 cls.lpszMenuName = NULL;
8045 cls.lpszClassName = "TestWindowClass";
8046 if(!RegisterClassA(&cls)) return FALSE;
8047
8048 cls.lpfnWndProc = HotkeyMsgCheckProcA;
8049 cls.lpszClassName = "HotkeyWindowClass";
8050 if(!RegisterClassA(&cls)) return FALSE;
8051
8052 cls.lpfnWndProc = ShowWindowProcA;
8053 cls.lpszClassName = "ShowWindowClass";
8054 if(!RegisterClassA(&cls)) return FALSE;
8055
8056 cls.lpfnWndProc = PopupMsgCheckProcA;
8057 cls.lpszClassName = "TestPopupClass";
8058 if(!RegisterClassA(&cls)) return FALSE;
8059
8060 cls.lpfnWndProc = ParentMsgCheckProcA;
8061 cls.lpszClassName = "TestParentClass";
8062 if(!RegisterClassA(&cls)) return FALSE;
8063
8064 cls.lpfnWndProc = StopQuitMsgCheckProcA;
8065 cls.lpszClassName = "StopQuitClass";
8066 if(!RegisterClassA(&cls)) return FALSE;
8067
8068 cls.lpfnWndProc = DefWindowProcA;
8069 cls.lpszClassName = "SimpleWindowClass";
8070 if(!RegisterClassA(&cls)) return FALSE;
8071
8072 cls.lpfnWndProc = PaintLoopProcA;
8073 cls.lpszClassName = "PaintLoopWindowClass";
8074 if(!RegisterClassA(&cls)) return FALSE;
8075
8076 cls.style = CS_NOCLOSE;
8077 cls.lpszClassName = "NoCloseWindowClass";
8078 if(!RegisterClassA(&cls)) return FALSE;
8079
8080 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
8081 cls.style = 0;
8082 cls.hInstance = GetModuleHandleA(0);
8083 cls.hbrBackground = 0;
8084 cls.lpfnWndProc = TestDlgProcA;
8085 cls.lpszClassName = "TestDialogClass";
8086 if(!RegisterClassA(&cls)) return FALSE;
8087
8088 clsW.style = 0;
8089 clsW.lpfnWndProc = MsgCheckProcW;
8090 clsW.cbClsExtra = 0;
8091 clsW.cbWndExtra = 0;
8092 clsW.hInstance = GetModuleHandleW(0);
8093 clsW.hIcon = 0;
8094 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
8095 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
8096 clsW.lpszMenuName = NULL;
8097 clsW.lpszClassName = testWindowClassW;
8098 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
8099
8100 return TRUE;
8101 }
8102
8103 static BOOL is_our_logged_class(HWND hwnd)
8104 {
8105 char buf[256];
8106
8107 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8108 {
8109 if (!lstrcmpiA(buf, "TestWindowClass") ||
8110 !lstrcmpiA(buf, "ShowWindowClass") ||
8111 !lstrcmpiA(buf, "TestParentClass") ||
8112 !lstrcmpiA(buf, "TestPopupClass") ||
8113 !lstrcmpiA(buf, "SimpleWindowClass") ||
8114 !lstrcmpiA(buf, "TestDialogClass") ||
8115 !lstrcmpiA(buf, "MDI_frame_class") ||
8116 !lstrcmpiA(buf, "MDI_client_class") ||
8117 !lstrcmpiA(buf, "MDI_child_class") ||
8118 !lstrcmpiA(buf, "my_button_class") ||
8119 !lstrcmpiA(buf, "my_edit_class") ||
8120 !lstrcmpiA(buf, "static") ||
8121 !lstrcmpiA(buf, "ListBox") ||
8122 !lstrcmpiA(buf, "ComboBox") ||
8123 !lstrcmpiA(buf, "MyDialogClass") ||
8124 !lstrcmpiA(buf, "#32770") ||
8125 !lstrcmpiA(buf, "#32768"))
8126 return TRUE;
8127 }
8128 return FALSE;
8129 }
8130
8131 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
8132 {
8133 HWND hwnd;
8134
8135 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
8136
8137 if (nCode == HCBT_CLICKSKIPPED)
8138 {
8139 /* ignore this event, XP sends it a lot when switching focus between windows */
8140 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8141 }
8142
8143 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
8144 {
8145 struct recvd_message msg;
8146
8147 msg.hwnd = 0;
8148 msg.message = nCode;
8149 msg.flags = hook|wparam|lparam;
8150 msg.wParam = wParam;
8151 msg.lParam = lParam;
8152 msg.descr = "CBT";
8153 add_message(&msg);
8154
8155 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8156 }
8157
8158 if (nCode == HCBT_DESTROYWND)
8159 {
8160 if (test_DestroyWindow_flag)
8161 {
8162 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
8163 if (style & WS_CHILD)
8164 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
8165 else if (style & WS_POPUP)
8166 lParam = WND_POPUP_ID;
8167 else
8168 lParam = WND_PARENT_ID;
8169 }
8170 }
8171
8172 /* Log also SetFocus(0) calls */
8173 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8174
8175 if (is_our_logged_class(hwnd))
8176 {
8177 struct recvd_message msg;
8178
8179 msg.hwnd = hwnd;
8180 msg.message = nCode;
8181 msg.flags = hook|wparam|lparam;
8182 msg.wParam = wParam;
8183 msg.lParam = lParam;
8184 msg.descr = "CBT";
8185 add_message(&msg);
8186 }
8187 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8188 }
8189
8190 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
8191 DWORD event,
8192 HWND hwnd,
8193 LONG object_id,
8194 LONG child_id,
8195 DWORD thread_id,
8196 DWORD event_time)
8197 {
8198 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
8199
8200 /* ignore mouse cursor events */
8201 if (object_id == OBJID_CURSOR) return;
8202
8203 if (!hwnd || is_our_logged_class(hwnd))
8204 {
8205 struct recvd_message msg;
8206
8207 msg.hwnd = hwnd;
8208 msg.message = event;
8209 msg.flags = winevent_hook|wparam|lparam;
8210 msg.wParam = object_id;
8211 msg.lParam = child_id;
8212 msg.descr = "WEH";
8213 add_message(&msg);
8214 }
8215 }
8216
8217 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
8218 static const WCHAR wszAnsi[] = {'U',0};
8219
8220 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
8221 {
8222 switch (uMsg)
8223 {
8224 case CB_FINDSTRINGEXACT:
8225 trace("String: %p\n", (LPCWSTR)lParam);
8226 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
8227 return 1;
8228 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
8229 return 0;
8230 return -1;
8231 }
8232 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
8233 }
8234
8235 static const struct message WmGetTextLengthAfromW[] = {
8236 { WM_GETTEXTLENGTH, sent },
8237 { WM_GETTEXT, sent|optional },
8238 { 0 }
8239 };
8240
8241 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
8242
8243 /* dummy window proc for WM_GETTEXTLENGTH test */
8244 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
8245 {
8246 switch(msg)
8247 {
8248 case WM_GETTEXTLENGTH:
8249 return lstrlenW(dummy_window_text) + 37; /* some random length */
8250 case WM_GETTEXT:
8251 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
8252 return lstrlenW( (LPWSTR)lp );
8253 default:
8254 return DefWindowProcW( hwnd, msg, wp, lp );
8255 }
8256 }
8257
8258 static void test_message_conversion(void)
8259 {
8260 static const WCHAR wszMsgConversionClass[] =
8261 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
8262 WNDCLASSW cls;
8263 LRESULT lRes;
8264 HWND hwnd;
8265 WNDPROC wndproc, newproc;
8266 BOOL ret;
8267
8268 cls.style = 0;
8269 cls.lpfnWndProc = MsgConversionProcW;
8270 cls.cbClsExtra = 0;
8271 cls.cbWndExtra = 0;
8272 cls.hInstance = GetModuleHandleW(NULL);
8273 cls.hIcon = NULL;
8274 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
8275 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
8276 cls.lpszMenuName = NULL;
8277 cls.lpszClassName = wszMsgConversionClass;
8278 /* this call will fail on Win9x, but that doesn't matter as this test is
8279 * meaningless on those platforms */
8280 if(!RegisterClassW(&cls)) return;
8281
8282 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
8283 100, 100, 200, 200, 0, 0, 0, NULL);
8284 ok(hwnd != NULL, "Window creation failed\n");
8285
8286 /* {W, A} -> A */
8287
8288 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
8289 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8290 ok(lRes == 0, "String should have been converted\n");
8291 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8292 ok(lRes == 1, "String shouldn't have been converted\n");
8293
8294 /* {W, A} -> W */
8295
8296 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
8297 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8298 ok(lRes == 1, "String shouldn't have been converted\n");
8299 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8300 ok(lRes == 1, "String shouldn't have been converted\n");
8301
8302 /* Synchronous messages */
8303
8304 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8305 ok(lRes == 0, "String should have been converted\n");
8306 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8307 ok(lRes == 1, "String shouldn't have been converted\n");
8308
8309 /* Asynchronous messages */
8310
8311 SetLastError(0);
8312 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8313 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8314 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8315 SetLastError(0);
8316 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8317 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8318 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8319 SetLastError(0);
8320 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8321 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8322 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8323 SetLastError(0);
8324 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8325 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8326 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8327 SetLastError(0);
8328 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8329 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8330 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8331 SetLastError(0);
8332 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8333 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8334 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8335 SetLastError(0);
8336 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8337 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8338 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8339 SetLastError(0);
8340 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8341 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8342 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8343
8344 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
8345
8346 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
8347 WS_OVERLAPPEDWINDOW,
8348 100, 100, 200, 200, 0, 0, 0, NULL);
8349 assert(hwnd);
8350 flush_sequence();
8351 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
8352 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8353 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8354 "got bad length %ld\n", lRes );
8355
8356 flush_sequence();
8357 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
8358 hwnd, WM_GETTEXTLENGTH, 0, 0);
8359 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8360 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8361 "got bad length %ld\n", lRes );
8362
8363 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
8364 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
8365 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8366 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8367 NULL, 0, NULL, NULL ) ||
8368 broken(lRes == lstrlenW(dummy_window_text) + 37),
8369 "got bad length %ld\n", lRes );
8370
8371 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
8372 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8373 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8374 NULL, 0, NULL, NULL ) ||
8375 broken(lRes == lstrlenW(dummy_window_text) + 37),
8376 "got bad length %ld\n", lRes );
8377
8378 ret = DestroyWindow(hwnd);
8379 ok( ret, "DestroyWindow() error %d\n", GetLastError());
8380 }
8381
8382 struct timer_info
8383 {
8384 HWND hWnd;
8385 HANDLE handles[2];
8386 DWORD id;
8387 };
8388
8389 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8390 {
8391 }
8392
8393 #define TIMER_ID 0x19
8394 #define TIMER_COUNT_EXPECTED 100
8395 #define TIMER_COUNT_TOLERANCE 10
8396
8397 static int count = 0;
8398 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
8399 {
8400 count++;
8401 }
8402
8403 static DWORD WINAPI timer_thread_proc(LPVOID x)
8404 {
8405 struct timer_info *info = x;
8406 DWORD r;
8407
8408 r = KillTimer(info->hWnd, 0x19);
8409 ok(r,"KillTimer failed in thread\n");
8410 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
8411 ok(r,"SetTimer failed in thread\n");
8412 ok(r==TIMER_ID,"SetTimer id different\n");
8413 r = SetEvent(info->handles[0]);
8414 ok(r,"SetEvent failed in thread\n");
8415 return 0;
8416 }
8417
8418 static void test_timers(void)
8419 {
8420 struct timer_info info;
8421 DWORD start;
8422 DWORD id;
8423 MSG msg;
8424
8425 info.hWnd = CreateWindowA("TestWindowClass", NULL,
8426 WS_OVERLAPPEDWINDOW ,
8427 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8428 NULL, NULL, 0);
8429
8430 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
8431 ok(info.id, "SetTimer failed\n");
8432 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
8433 info.handles[0] = CreateEventW(NULL,0,0,NULL);
8434 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
8435
8436 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
8437
8438 WaitForSingleObject(info.handles[1], INFINITE);
8439
8440 CloseHandle(info.handles[0]);
8441 CloseHandle(info.handles[1]);
8442
8443 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
8444
8445 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
8446 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
8447 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
8448 * ±9 counts (~4 ms) around the expected value.
8449 */
8450 count = 0;
8451 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
8452 ok(id != 0, "did not get id from SetTimer.\n");
8453 ok(id==TIMER_ID, "SetTimer timer ID different\n");
8454 start = GetTickCount();
8455 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
8456 DispatchMessageA(&msg);
8457 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
8458 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
8459 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
8460 "did not get expected count for minimum timeout (%d != ~%d).\n",
8461 count, TIMER_COUNT_EXPECTED);
8462 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
8463 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
8464 if (pSetSystemTimer)
8465 {
8466 int syscount = 0;
8467
8468 count = 0;
8469 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
8470 ok(id != 0, "did not get id from SetSystemTimer.\n");
8471 ok(id==TIMER_ID, "SetTimer timer ID different\n");
8472 start = GetTickCount();
8473 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
8474 {
8475 if (msg.message == WM_SYSTIMER)
8476 syscount++;
8477 DispatchMessageA(&msg);
8478 }
8479 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
8480 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
8481 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
8482 "did not get expected count for minimum timeout (%d != ~%d).\n",
8483 syscount, TIMER_COUNT_EXPECTED);
8484 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
8485 count);
8486 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
8487 }
8488
8489 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8490 }
8491
8492 static void test_timers_no_wnd(void)
8493 {
8494 UINT_PTR id, id2;
8495 DWORD start;
8496 MSG msg;
8497
8498 count = 0;
8499 id = SetTimer(NULL, 0, 100, callback_count);
8500 ok(id != 0, "did not get id from SetTimer.\n");
8501 id2 = SetTimer(NULL, id, 200, callback_count);
8502 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
8503 Sleep(150);
8504 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8505 ok(count == 0, "did not get zero count as expected (%i).\n", count);
8506 Sleep(150);
8507 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8508 ok(count == 1, "did not get one count as expected (%i).\n", count);
8509 KillTimer(NULL, id);
8510 Sleep(250);
8511 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8512 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
8513
8514 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
8515 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
8516 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
8517 * ±9 counts (~4 ms) around the expected value.
8518 */
8519 count = 0;
8520 id = SetTimer(NULL, 0, 0, callback_count);
8521 ok(id != 0, "did not get id from SetTimer.\n");
8522 start = GetTickCount();
8523 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
8524 DispatchMessageA(&msg);
8525 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
8526 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
8527 "did not get expected count for minimum timeout (%d != ~%d).\n",
8528 count, TIMER_COUNT_EXPECTED);
8529 KillTimer(NULL, id);
8530 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
8531 }
8532
8533 /* Various win events with arbitrary parameters */
8534 static const struct message WmWinEventsSeq[] = {
8535 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8536 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8537 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8538 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8539 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8540 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8541 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8542 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8543 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8544 /* our win event hook ignores OBJID_CURSOR events */
8545 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
8546 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
8547 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
8548 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
8549 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
8550 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8551 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8552 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8553 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8554 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8555 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8556 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8557 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8558 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8559 { 0 }
8560 };
8561 static const struct message WmWinEventCaretSeq[] = {
8562 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8563 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8564 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
8565 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8566 { 0 }
8567 };
8568 static const struct message WmWinEventCaretSeq_2[] = {
8569 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8570 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8571 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8572 { 0 }
8573 };
8574 static const struct message WmWinEventAlertSeq[] = {
8575 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
8576 { 0 }
8577 };
8578 static const struct message WmWinEventAlertSeq_2[] = {
8579 /* create window in the thread proc */
8580 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
8581 /* our test event */
8582 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
8583 { 0 }
8584 };
8585 static const struct message WmGlobalHookSeq_1[] = {
8586 /* create window in the thread proc */
8587 { HCBT_CREATEWND, hook|lparam, 0, 2 },
8588 /* our test events */
8589 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
8590 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
8591 { 0 }
8592 };
8593 static const struct message WmGlobalHookSeq_2[] = {
8594 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
8595 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
8596 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
8597 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
8598 { 0 }
8599 };
8600
8601 static const struct message WmMouseLLHookSeq[] = {
8602 { WM_MOUSEMOVE, hook },
8603 { WM_LBUTTONUP, hook },
8604 { WM_MOUSEMOVE, hook },
8605 { 0 }
8606 };
8607
8608 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
8609 DWORD event,
8610 HWND hwnd,
8611 LONG object_id,
8612 LONG child_id,
8613 DWORD thread_id,
8614 DWORD event_time)
8615 {
8616 char buf[256];
8617
8618 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8619 {
8620 if (!lstrcmpiA(buf, "TestWindowClass") ||
8621 !lstrcmpiA(buf, "static"))
8622 {
8623 struct recvd_message msg;
8624
8625 msg.hwnd = hwnd;
8626 msg.message = event;
8627 msg.flags = winevent_hook|wparam|lparam;
8628 msg.wParam = object_id;
8629 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8630 msg.descr = "WEH_2";
8631 add_message(&msg);
8632 }
8633 }
8634 }
8635
8636 static HHOOK hCBT_global_hook;
8637 static DWORD cbt_global_hook_thread_id;
8638
8639 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
8640 {
8641 HWND hwnd;
8642 char buf[256];
8643
8644 if (nCode == HCBT_SYSCOMMAND)
8645 {
8646 struct recvd_message msg;
8647
8648 msg.hwnd = 0;
8649 msg.message = nCode;
8650 msg.flags = hook|wparam|lparam;
8651 msg.wParam = wParam;
8652 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8653 msg.descr = "CBT_2";
8654 add_message(&msg);
8655
8656 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8657 }
8658 /* WH_MOUSE_LL hook */
8659 if (nCode == HC_ACTION)
8660 {
8661 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8662
8663 /* we can't test for real mouse events */
8664 if (mhll->flags & LLMHF_INJECTED)
8665 {
8666 struct recvd_message msg;
8667
8668 memset (&msg, 0, sizeof (msg));
8669 msg.message = wParam;
8670 msg.flags = hook;
8671 msg.descr = "CBT_2";
8672 add_message(&msg);
8673 }
8674 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8675 }
8676
8677 /* Log also SetFocus(0) calls */
8678 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8679
8680 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8681 {
8682 if (!lstrcmpiA(buf, "TestWindowClass") ||
8683 !lstrcmpiA(buf, "static"))
8684 {
8685 struct recvd_message msg;
8686
8687 msg.hwnd = hwnd;
8688 msg.message = nCode;
8689 msg.flags = hook|wparam|lparam;
8690 msg.wParam = wParam;
8691 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8692 msg.descr = "CBT_2";
8693 add_message(&msg);
8694 }
8695 }
8696 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8697 }
8698
8699 static DWORD WINAPI win_event_global_thread_proc(void *param)
8700 {
8701 HWND hwnd;
8702 MSG msg;
8703 HANDLE hevent = *(HANDLE *)param;
8704
8705 assert(pNotifyWinEvent);
8706
8707 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8708 assert(hwnd);
8709 trace("created thread window %p\n", hwnd);
8710
8711 *(HWND *)param = hwnd;
8712
8713 flush_sequence();
8714 /* this event should be received only by our new hook proc,
8715 * an old one does not expect an event from another thread.
8716 */
8717 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8718 SetEvent(hevent);
8719
8720 while (GetMessageA(&msg, 0, 0, 0))
8721 {
8722 TranslateMessage(&msg);
8723 DispatchMessageA(&msg);
8724 }
8725 return 0;
8726 }
8727
8728 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8729 {
8730 HWND hwnd;
8731 MSG msg;
8732 HANDLE hevent = *(HANDLE *)param;
8733
8734 flush_sequence();
8735 /* these events should be received only by our new hook proc,
8736 * an old one does not expect an event from another thread.
8737 */
8738
8739 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8740 assert(hwnd);
8741 trace("created thread window %p\n", hwnd);
8742
8743 *(HWND *)param = hwnd;
8744
8745 /* Windows doesn't like when a thread plays games with the focus,
8746 that leads to all kinds of misbehaviours and failures to activate
8747 a window. So, better keep next lines commented out.
8748 SetFocus(0);
8749 SetFocus(hwnd);*/
8750
8751 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8752 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8753
8754 SetEvent(hevent);
8755
8756 while (GetMessageA(&msg, 0, 0, 0))
8757 {
8758 TranslateMessage(&msg);
8759 DispatchMessageA(&msg);
8760 }
8761 return 0;
8762 }
8763
8764 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8765 {
8766 HWND hwnd;
8767 MSG msg;
8768 HANDLE hevent = *(HANDLE *)param;
8769
8770 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8771 assert(hwnd);
8772 trace("created thread window %p\n", hwnd);
8773
8774 *(HWND *)param = hwnd;
8775
8776 flush_sequence();
8777
8778 /* Windows doesn't like when a thread plays games with the focus,
8779 * that leads to all kinds of misbehaviours and failures to activate
8780 * a window. So, better don't generate a mouse click message below.
8781 */
8782 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8783 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8784 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8785
8786 SetEvent(hevent);
8787 while (GetMessageA(&msg, 0, 0, 0))
8788 {
8789 TranslateMessage(&msg);
8790 DispatchMessageA(&msg);
8791 }
8792 return 0;
8793 }
8794
8795 static void test_winevents(void)
8796 {
8797 BOOL ret;
8798 MSG msg;
8799 HWND hwnd, hwnd2;
8800 UINT i;
8801 HANDLE hthread, hevent;
8802 DWORD tid;
8803 HWINEVENTHOOK hhook;
8804 const struct message *events = WmWinEventsSeq;
8805
8806 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8807 WS_OVERLAPPEDWINDOW,
8808 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8809 NULL, NULL, 0);
8810 assert(hwnd);
8811
8812 /****** start of global hook test *************/
8813 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8814 if (!hCBT_global_hook)
8815 {
8816 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8817 skip( "cannot set global hook\n" );
8818 return;
8819 }
8820
8821 hevent = CreateEventA(NULL, 0, 0, NULL);
8822 assert(hevent);
8823 hwnd2 = hevent;
8824
8825 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8826 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8827
8828 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8829
8830 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8831
8832 flush_sequence();
8833 /* this one should be received only by old hook proc */
8834 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8835 /* this one should be received only by old hook proc */
8836 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8837
8838 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8839
8840 ret = UnhookWindowsHookEx(hCBT_global_hook);
8841 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8842
8843 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8844 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8845 CloseHandle(hthread);
8846 CloseHandle(hevent);
8847 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8848 /****** end of global hook test *************/
8849
8850 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8851 {
8852 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8853 return;
8854 }
8855
8856 flush_sequence();
8857
8858 if (0)
8859 {
8860 /* this test doesn't pass under Win9x */
8861 /* win2k ignores events with hwnd == 0 */
8862 SetLastError(0xdeadbeef);
8863 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8864 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8865 GetLastError() == 0xdeadbeef, /* Win9x */
8866 "unexpected error %d\n", GetLastError());
8867 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8868 }
8869
8870 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8871 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8872
8873 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8874
8875 /****** start of event filtering test *************/
8876 hhook = pSetWinEventHook(
8877 EVENT_OBJECT_SHOW, /* 0x8002 */
8878 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8879 GetModuleHandleA(0), win_event_global_hook_proc,
8880 GetCurrentProcessId(), 0,
8881 WINEVENT_INCONTEXT);
8882 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8883
8884 hevent = CreateEventA(NULL, 0, 0, NULL);
8885 assert(hevent);
8886 hwnd2 = hevent;
8887
8888 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8889 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8890
8891 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8892
8893 ok_sequence(WmWinEventAlertSeq, "alert winevent", 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, "caret winevent", FALSE);
8903
8904 ret = pUnhookWinEvent(hhook);
8905 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8906
8907 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8908 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8909 CloseHandle(hthread);
8910 CloseHandle(hevent);
8911 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8912 /****** end of event filtering test *************/
8913
8914 /****** start of out of context event test *************/
8915 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8916 win_event_global_hook_proc, GetCurrentProcessId(), 0,
8917 WINEVENT_OUTOFCONTEXT);
8918 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8919
8920 hevent = CreateEventA(NULL, 0, 0, NULL);
8921 assert(hevent);
8922 hwnd2 = hevent;
8923
8924 flush_sequence();
8925
8926 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8927 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8928
8929 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8930
8931 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8932 /* process pending winevent messages */
8933 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8934 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8935
8936 flush_sequence();
8937 /* this one should be received only by old hook proc */
8938 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8939 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8940 /* this one should be received only by old hook proc */
8941 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8942
8943 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8944 /* process pending winevent messages */
8945 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8946 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8947
8948 ret = pUnhookWinEvent(hhook);
8949 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8950
8951 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8952 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8953 CloseHandle(hthread);
8954 CloseHandle(hevent);
8955 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8956 /****** end of out of context event test *************/
8957
8958 /****** start of MOUSE_LL hook test *************/
8959 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8960 /* WH_MOUSE_LL is not supported on Win9x platforms */
8961 if (!hCBT_global_hook)
8962 {
8963 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8964 goto skip_mouse_ll_hook_test;
8965 }
8966
8967 hevent = CreateEventA(NULL, 0, 0, NULL);
8968 assert(hevent);
8969 hwnd2 = hevent;
8970
8971 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8972 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8973
8974 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8975 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8976
8977 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8978 flush_sequence();
8979
8980 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8981 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8982 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8983
8984 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8985
8986 ret = UnhookWindowsHookEx(hCBT_global_hook);
8987 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8988
8989 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8990 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8991 CloseHandle(hthread);
8992 CloseHandle(hevent);
8993 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8994 /****** end of MOUSE_LL hook test *************/
8995 skip_mouse_ll_hook_test:
8996
8997 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8998 }
8999
9000 static void test_set_hook(void)
9001 {
9002 BOOL ret;
9003 HHOOK hhook;
9004 HWINEVENTHOOK hwinevent_hook;
9005
9006 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
9007 ok(hhook != 0, "local hook does not require hModule set to 0\n");
9008 UnhookWindowsHookEx(hhook);
9009
9010 if (0)
9011 {
9012 /* this test doesn't pass under Win9x: BUG! */
9013 SetLastError(0xdeadbeef);
9014 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
9015 ok(!hhook, "global hook requires hModule != 0\n");
9016 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
9017 }
9018
9019 SetLastError(0xdeadbeef);
9020 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
9021 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
9022 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
9023 GetLastError() == 0xdeadbeef, /* Win9x */
9024 "unexpected error %d\n", GetLastError());
9025
9026 SetLastError(0xdeadbeef);
9027 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
9028 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
9029 GetLastError() == 0xdeadbeef, /* Win9x */
9030 "unexpected error %d\n", GetLastError());
9031
9032 if (!pSetWinEventHook || !pUnhookWinEvent) return;
9033
9034 /* even process local incontext hooks require hmodule */
9035 SetLastError(0xdeadbeef);
9036 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
9037 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
9038 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
9039 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
9040 GetLastError() == 0xdeadbeef, /* Win9x */
9041 "unexpected error %d\n", GetLastError());
9042
9043 /* even thread local incontext hooks require hmodule */
9044 SetLastError(0xdeadbeef);
9045 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
9046 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
9047 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
9048 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
9049 GetLastError() == 0xdeadbeef, /* Win9x */
9050 "unexpected error %d\n", GetLastError());
9051
9052 if (0)
9053 {
9054 /* these 3 tests don't pass under Win9x */
9055 SetLastError(0xdeadbeef);
9056 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
9057 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
9058 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
9059 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
9060
9061 SetLastError(0xdeadbeef);
9062 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
9063 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
9064 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
9065 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
9066
9067 SetLastError(0xdeadbeef);
9068 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
9069 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
9070 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
9071 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
9072 }
9073
9074 SetLastError(0xdeadbeef);
9075 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
9076 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
9077 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
9078 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
9079 ret = pUnhookWinEvent(hwinevent_hook);
9080 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9081
9082 todo_wine {
9083 /* This call succeeds under win2k SP4, but fails under Wine.
9084 Does win2k test/use passed process id? */
9085 SetLastError(0xdeadbeef);
9086 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
9087 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
9088 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
9089 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
9090 ret = pUnhookWinEvent(hwinevent_hook);
9091 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9092 }
9093
9094 SetLastError(0xdeadbeef);
9095 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
9096 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
9097 GetLastError() == 0xdeadbeef, /* Win9x */
9098 "unexpected error %d\n", GetLastError());
9099 }
9100
9101 static const struct message ScrollWindowPaint1[] = {
9102 { WM_PAINT, sent },
9103 { WM_ERASEBKGND, sent|beginpaint },
9104 { WM_GETTEXTLENGTH, sent|optional },
9105 { WM_PAINT, sent|optional },
9106 { WM_NCPAINT, sent|beginpaint|optional },
9107 { WM_GETTEXT, sent|beginpaint|optional },
9108 { WM_GETTEXT, sent|beginpaint|optional },
9109 { WM_GETTEXT, sent|beginpaint|optional },
9110 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
9111 { WM_ERASEBKGND, sent|beginpaint|optional },
9112 { 0 }
9113 };
9114
9115 static const struct message ScrollWindowPaint2[] = {
9116 { WM_PAINT, sent },
9117 { 0 }
9118 };
9119
9120 static void test_scrollwindowex(void)
9121 {
9122 HWND hwnd, hchild;
9123 RECT rect={0,0,130,130};
9124
9125 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
9126 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
9127 100, 100, 200, 200, 0, 0, 0, NULL);
9128 ok (hwnd != 0, "Failed to create overlapped window\n");
9129 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
9130 WS_VISIBLE|WS_CAPTION|WS_CHILD,
9131 10, 10, 150, 150, hwnd, 0, 0, NULL);
9132 ok (hchild != 0, "Failed to create child\n");
9133 UpdateWindow(hwnd);
9134 flush_events();
9135 flush_sequence();
9136
9137 /* scroll without the child window */
9138 trace("start scroll\n");
9139 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
9140 SW_ERASE|SW_INVALIDATE);
9141 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
9142 trace("end scroll\n");
9143 flush_sequence();
9144 flush_events();
9145 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
9146 flush_events();
9147 flush_sequence();
9148
9149 /* Now without the SW_ERASE flag */
9150 trace("start scroll\n");
9151 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
9152 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
9153 trace("end scroll\n");
9154 flush_sequence();
9155 flush_events();
9156 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
9157 flush_events();
9158 flush_sequence();
9159
9160 /* now scroll the child window as well */
9161 trace("start scroll\n");
9162 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
9163 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
9164 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
9165 /* windows sometimes a WM_MOVE */
9166 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
9167 trace("end scroll\n");
9168 flush_sequence();
9169 flush_events();
9170 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
9171 flush_events();
9172 flush_sequence();
9173
9174 /* now scroll with ScrollWindow() */
9175 trace("start scroll with ScrollWindow\n");
9176 ScrollWindow( hwnd, 5, 5, NULL, NULL);
9177 trace("end scroll\n");
9178 flush_sequence();
9179 flush_events();
9180 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
9181
9182 ok(DestroyWindow(hchild), "failed to destroy window\n");
9183 ok(DestroyWindow(hwnd), "failed to destroy window\n");
9184 flush_sequence();
9185 }
9186
9187 static const struct message destroy_window_with_children[] = {
9188 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
9189 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
9190 { 0x0090, sent|optional },
9191 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
9192 { 0x0090, sent|optional },
9193 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
9194 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9195 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9196 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9197 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
9198 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
9199 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
9200 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
9201 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
9202 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
9203 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
9204 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
9205 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
9206 { 0 }
9207 };
9208
9209 static void test_DestroyWindow(void)
9210 {
9211 BOOL ret;
9212 HWND parent, child1, child2, child3, child4, test;
9213 UINT_PTR child_id = WND_CHILD_ID + 1;
9214
9215 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9216 100, 100, 200, 200, 0, 0, 0, NULL);
9217 assert(parent != 0);
9218 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9219 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
9220 assert(child1 != 0);
9221 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9222 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
9223 assert(child2 != 0);
9224 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9225 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
9226 assert(child3 != 0);
9227 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
9228 0, 0, 50, 50, parent, 0, 0, NULL);
9229 assert(child4 != 0);
9230
9231 /* test owner/parent of child2 */
9232 test = GetParent(child2);
9233 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9234 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
9235 if(pGetAncestor) {
9236 test = pGetAncestor(child2, GA_PARENT);
9237 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9238 }
9239 test = GetWindow(child2, GW_OWNER);
9240 ok(!test, "wrong owner %p\n", test);
9241
9242 test = SetParent(child2, parent);
9243 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
9244
9245 /* test owner/parent of the parent */
9246 test = GetParent(parent);
9247 ok(!test, "wrong parent %p\n", test);
9248 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
9249 if(pGetAncestor) {
9250 test = pGetAncestor(parent, GA_PARENT);
9251 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9252 }
9253 test = GetWindow(parent, GW_OWNER);
9254 ok(!test, "wrong owner %p\n", test);
9255
9256 /* test owner/parent of child1 */
9257 test = GetParent(child1);
9258 ok(test == parent, "wrong parent %p\n", test);
9259 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
9260 if(pGetAncestor) {
9261 test = pGetAncestor(child1, GA_PARENT);
9262 ok(test == parent, "wrong parent %p\n", test);
9263 }
9264 test = GetWindow(child1, GW_OWNER);
9265 ok(!test, "wrong owner %p\n", test);
9266
9267 /* test owner/parent of child2 */
9268 test = GetParent(child2);
9269 ok(test == parent, "wrong parent %p\n", test);
9270 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
9271 if(pGetAncestor) {
9272 test = pGetAncestor(child2, GA_PARENT);
9273 ok(test == parent, "wrong parent %p\n", test);
9274 }
9275 test = GetWindow(child2, GW_OWNER);
9276 ok(!test, "wrong owner %p\n", test);
9277
9278 /* test owner/parent of child3 */
9279 test = GetParent(child3);
9280 ok(test == child1, "wrong parent %p\n", test);
9281 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
9282 if(pGetAncestor) {
9283 test = pGetAncestor(child3, GA_PARENT);
9284 ok(test == child1, "wrong parent %p\n", test);
9285 }
9286 test = GetWindow(child3, GW_OWNER);
9287 ok(!test, "wrong owner %p\n", test);
9288
9289 /* test owner/parent of child4 */
9290 test = GetParent(child4);
9291 ok(test == parent, "wrong parent %p\n", test);
9292 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
9293 if(pGetAncestor) {
9294 test = pGetAncestor(child4, GA_PARENT);
9295 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9296 }
9297 test = GetWindow(child4, GW_OWNER);
9298 ok(test == parent, "wrong owner %p\n", test);
9299
9300 flush_sequence();
9301
9302 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
9303 parent, child1, child2, child3, child4);
9304
9305 SetCapture(child4);
9306 test = GetCapture();
9307 ok(test == child4, "wrong capture window %p\n", test);
9308
9309 test_DestroyWindow_flag = TRUE;
9310 ret = DestroyWindow(parent);
9311 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9312 test_DestroyWindow_flag = FALSE;
9313 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
9314
9315 ok(!IsWindow(parent), "parent still exists\n");
9316 ok(!IsWindow(child1), "child1 still exists\n");
9317 ok(!IsWindow(child2), "child2 still exists\n");
9318 ok(!IsWindow(child3), "child3 still exists\n");
9319 ok(!IsWindow(child4), "child4 still exists\n");
9320
9321 test = GetCapture();
9322 ok(!test, "wrong capture window %p\n", test);
9323 }
9324
9325
9326 static const struct message WmDispatchPaint[] = {
9327 { WM_NCPAINT, sent },
9328 { WM_GETTEXT, sent|defwinproc|optional },
9329 { WM_GETTEXT, sent|defwinproc|optional },
9330 { WM_ERASEBKGND, sent },
9331 { 0 }
9332 };
9333
9334 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9335 {
9336 if (message == WM_PAINT) return 0;
9337 return MsgCheckProcA( hwnd, message, wParam, lParam );
9338 }
9339
9340 static void test_DispatchMessage(void)
9341 {
9342 RECT rect;
9343 MSG msg;
9344 int count;
9345 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9346 100, 100, 200, 200, 0, 0, 0, NULL);
9347 ShowWindow( hwnd, SW_SHOW );
9348 UpdateWindow( hwnd );
9349 flush_events();
9350 flush_sequence();
9351 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
9352
9353 SetRect( &rect, -5, -5, 5, 5 );
9354 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9355 count = 0;
9356 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9357 {
9358 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9359 else
9360 {
9361 flush_sequence();
9362 DispatchMessageA( &msg );
9363 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
9364 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9365 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
9366 if (++count > 10) break;
9367 }
9368 }
9369 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
9370
9371 trace("now without DispatchMessage\n");
9372 flush_sequence();
9373 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9374 count = 0;
9375 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9376 {
9377 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9378 else
9379 {
9380 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
9381 flush_sequence();
9382 /* this will send WM_NCCPAINT just like DispatchMessage does */
9383 GetUpdateRgn( hwnd, hrgn, TRUE );
9384 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9385 DeleteObject( hrgn );
9386 GetClientRect( hwnd, &rect );
9387 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
9388 ok( !count, "Got multiple WM_PAINTs\n" );
9389 if (++count > 10) break;
9390 }
9391 }
9392
9393 flush_sequence();
9394 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9395 count = 0;
9396 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9397 {
9398 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9399 else
9400 {
9401 HDC hdc;
9402
9403 flush_sequence();
9404 hdc = BeginPaint( hwnd, NULL );
9405 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
9406 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
9407 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9408 ok( !count, "Got multiple WM_PAINTs\n" );
9409 if (++count > 10) break;
9410 }
9411 }
9412 DestroyWindow(hwnd);
9413 }
9414
9415
9416 static const struct message WmUser[] = {
9417 { WM_USER, sent },
9418 { 0 }
9419 };
9420
9421 struct sendmsg_info
9422 {
9423 HWND hwnd;
9424 DWORD timeout;
9425 DWORD ret;
9426 };
9427
9428 static DWORD CALLBACK send_msg_thread( LPVOID arg )
9429 {
9430 struct sendmsg_info *info = arg;
9431 SetLastError( 0xdeadbeef );
9432 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
9433 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
9434 broken(GetLastError() == 0), /* win9x */
9435 "unexpected error %d\n", GetLastError());
9436 return 0;
9437 }
9438
9439 static void wait_for_thread( HANDLE thread )
9440 {
9441 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
9442 {
9443 MSG msg;
9444 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
9445 }
9446 }
9447
9448 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9449 {
9450 if (message == WM_USER) Sleep(200);
9451 return MsgCheckProcA( hwnd, message, wParam, lParam );
9452 }
9453
9454 static void test_SendMessageTimeout(void)
9455 {
9456 HANDLE thread;
9457 struct sendmsg_info info;
9458 DWORD tid;
9459 BOOL is_win9x;
9460
9461 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9462 100, 100, 200, 200, 0, 0, 0, NULL);
9463 flush_events();
9464 flush_sequence();
9465
9466 info.timeout = 1000;
9467 info.ret = 0xdeadbeef;
9468 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9469 wait_for_thread( thread );
9470 CloseHandle( thread );
9471 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9472 ok_sequence( WmUser, "WmUser", FALSE );
9473
9474 info.timeout = 1;
9475 info.ret = 0xdeadbeef;
9476 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9477 Sleep(100); /* SendMessageTimeout should time out here */
9478 wait_for_thread( thread );
9479 CloseHandle( thread );
9480 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9481 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9482
9483 /* 0 means infinite timeout (but not on win9x) */
9484 info.timeout = 0;
9485 info.ret = 0xdeadbeef;
9486 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9487 Sleep(100);
9488 wait_for_thread( thread );
9489 CloseHandle( thread );
9490 is_win9x = !info.ret;
9491 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9492 else ok_sequence( WmUser, "WmUser", FALSE );
9493
9494 /* timeout is treated as signed despite the prototype (but not on win9x) */
9495 info.timeout = 0x7fffffff;
9496 info.ret = 0xdeadbeef;
9497 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9498 Sleep(100);
9499 wait_for_thread( thread );
9500 CloseHandle( thread );
9501 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9502 ok_sequence( WmUser, "WmUser", FALSE );
9503
9504 info.timeout = 0x80000000;
9505 info.ret = 0xdeadbeef;
9506 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9507 Sleep(100);
9508 wait_for_thread( thread );
9509 CloseHandle( thread );
9510 if (is_win9x)
9511 {
9512 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9513 ok_sequence( WmUser, "WmUser", FALSE );
9514 }
9515 else
9516 {
9517 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9518 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9519 }
9520
9521 /* now check for timeout during message processing */
9522 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
9523 info.timeout = 100;
9524 info.ret = 0xdeadbeef;
9525 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9526 wait_for_thread( thread );
9527 CloseHandle( thread );
9528 /* we should time out but still get the message */
9529 ok( info.ret == 0, "SendMessageTimeout failed\n" );
9530 ok_sequence( WmUser, "WmUser", FALSE );
9531
9532 DestroyWindow( info.hwnd );
9533 }
9534
9535
9536 /****************** edit message test *************************/
9537 #define ID_EDIT 0x1234
9538 static const struct message sl_edit_setfocus[] =
9539 {
9540 { HCBT_SETFOCUS, hook },
9541 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9542 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9543 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9544 { WM_SETFOCUS, sent|wparam, 0 },
9545 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9546 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
9547 { WM_CTLCOLOREDIT, sent|parent },
9548 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9549 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9550 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9551 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9552 { 0 }
9553 };
9554 static const struct message sl_edit_invisible[] =
9555 {
9556 { HCBT_SETFOCUS, hook },
9557 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9558 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9559 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9560 { WM_KILLFOCUS, sent|parent },
9561 { WM_SETFOCUS, sent },
9562 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9563 { 0 }
9564 };
9565 static const struct message ml_edit_setfocus[] =
9566 {
9567 { HCBT_SETFOCUS, hook },
9568 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9569 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9570 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9571 { WM_SETFOCUS, sent|wparam, 0 },
9572 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9573 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9574 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9575 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9576 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9577 { 0 }
9578 };
9579 static const struct message sl_edit_killfocus[] =
9580 {
9581 { HCBT_SETFOCUS, hook },
9582 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9583 { WM_KILLFOCUS, sent|wparam, 0 },
9584 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9585 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9586 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
9587 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9588 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
9589 { 0 }
9590 };
9591 static const struct message sl_edit_lbutton_dblclk[] =
9592 {
9593 { WM_LBUTTONDBLCLK, sent },
9594 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9595 { 0 }
9596 };
9597 static const struct message sl_edit_lbutton_down[] =
9598 {
9599 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9600 { HCBT_SETFOCUS, hook },
9601 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9602 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9603 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9604 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9605 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9606 { WM_CTLCOLOREDIT, sent|parent },
9607 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9608 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9609 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9610 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9611 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9612 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9613 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9614 { WM_CTLCOLOREDIT, sent|parent|optional },
9615 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9616 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9617 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9618 { 0 }
9619 };
9620 static const struct message ml_edit_lbutton_down[] =
9621 {
9622 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9623 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9624 { HCBT_SETFOCUS, hook },
9625 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9626 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9627 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9628 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9629 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9630 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9631 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9632 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9633 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9634 { 0 }
9635 };
9636 static const struct message sl_edit_lbutton_up[] =
9637 {
9638 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9639 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9640 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9641 { WM_CAPTURECHANGED, sent|defwinproc },
9642 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9643 { 0 }
9644 };
9645 static const struct message ml_edit_lbutton_up[] =
9646 {
9647 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9648 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9649 { WM_CAPTURECHANGED, sent|defwinproc },
9650 { 0 }
9651 };
9652
9653 static WNDPROC old_edit_proc;
9654
9655 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9656 {
9657 static LONG defwndproc_counter = 0;
9658 LRESULT ret;
9659 struct recvd_message msg;
9660
9661 if (ignore_message( message )) return 0;
9662
9663 msg.hwnd = hwnd;
9664 msg.message = message;
9665 msg.flags = sent|wparam|lparam;
9666 if (defwndproc_counter) msg.flags |= defwinproc;
9667 msg.wParam = wParam;
9668 msg.lParam = lParam;
9669 msg.descr = "edit";
9670 add_message(&msg);
9671
9672 defwndproc_counter++;
9673 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9674 defwndproc_counter--;
9675
9676 return ret;
9677 }
9678
9679 static void subclass_edit(void)
9680 {
9681 WNDCLASSA cls;
9682
9683 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9684
9685 old_edit_proc = cls.lpfnWndProc;
9686
9687 cls.hInstance = GetModuleHandleA(NULL);
9688 cls.lpfnWndProc = edit_hook_proc;
9689 cls.lpszClassName = "my_edit_class";
9690 UnregisterClassA(cls.lpszClassName, cls.hInstance);
9691 if (!RegisterClassA(&cls)) assert(0);
9692 }
9693
9694 static void test_edit_messages(void)
9695 {
9696 HWND hwnd, parent;
9697 DWORD dlg_code;
9698
9699 subclass_edit();
9700 log_all_parent_messages++;
9701
9702 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9703 100, 100, 200, 200, 0, 0, 0, NULL);
9704 ok (parent != 0, "Failed to create parent window\n");
9705
9706 /* test single line edit */
9707 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9708 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9709 ok(hwnd != 0, "Failed to create edit window\n");
9710
9711 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9712 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9713
9714 flush_sequence();
9715 SetFocus(hwnd);
9716 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
9717
9718 ShowWindow(hwnd, SW_SHOW);
9719 UpdateWindow(hwnd);
9720 SetFocus(0);
9721 flush_sequence();
9722
9723 SetFocus(hwnd);
9724 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9725
9726 SetFocus(0);
9727 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9728
9729 SetFocus(0);
9730 ReleaseCapture();
9731 flush_sequence();
9732
9733 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9734 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9735
9736 SetFocus(0);
9737 ReleaseCapture();
9738 flush_sequence();
9739
9740 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9741 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9742
9743 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9744 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9745
9746 DestroyWindow(hwnd);
9747
9748 /* test multiline edit */
9749 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9750 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9751 ok(hwnd != 0, "Failed to create edit window\n");
9752
9753 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9754 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9755 "wrong dlg_code %08x\n", dlg_code);
9756
9757 ShowWindow(hwnd, SW_SHOW);
9758 UpdateWindow(hwnd);
9759 SetFocus(0);
9760 flush_sequence();
9761
9762 SetFocus(hwnd);
9763 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9764
9765 SetFocus(0);
9766 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9767
9768 SetFocus(0);
9769 ReleaseCapture();
9770 flush_sequence();
9771
9772 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9773 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9774
9775 SetFocus(0);
9776 ReleaseCapture();
9777 flush_sequence();
9778
9779 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9780 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9781
9782 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9783 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9784
9785 DestroyWindow(hwnd);
9786 DestroyWindow(parent);
9787
9788 log_all_parent_messages--;
9789 }
9790
9791 /**************************** End of Edit test ******************************/
9792
9793 static const struct message WmKeyDownSkippedSeq[] =
9794 {
9795 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9796 { 0 }
9797 };
9798 static const struct message WmKeyDownWasDownSkippedSeq[] =
9799 {
9800 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9801 { 0 }
9802 };
9803 static const struct message WmKeyUpSkippedSeq[] =
9804 {
9805 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9806 { 0 }
9807 };
9808 static const struct message WmUserKeyUpSkippedSeq[] =
9809 {
9810 { WM_USER, sent },
9811 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9812 { 0 }
9813 };
9814
9815 #define EV_STOP 0
9816 #define EV_SENDMSG 1
9817 #define EV_ACK 2
9818
9819 struct peekmsg_info
9820 {
9821 HWND hwnd;
9822 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9823 };
9824
9825 static DWORD CALLBACK send_msg_thread_2(void *param)
9826 {
9827 DWORD ret;
9828 struct peekmsg_info *info = param;
9829
9830 trace("thread: looping\n");
9831 SetEvent(info->hevent[EV_ACK]);
9832
9833 while (1)
9834 {
9835 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9836
9837 switch (ret)
9838 {
9839 case WAIT_OBJECT_0 + EV_STOP:
9840 trace("thread: exiting\n");
9841 return 0;
9842
9843 case WAIT_OBJECT_0 + EV_SENDMSG:
9844 trace("thread: sending message\n");
9845 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
9846 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
9847 SetEvent(info->hevent[EV_ACK]);
9848 break;
9849
9850 default:
9851 trace("unexpected return: %04x\n", ret);
9852 assert(0);
9853 break;
9854 }
9855 }
9856 return 0;
9857 }
9858
9859 static void test_PeekMessage(void)
9860 {
9861 MSG msg;
9862 HANDLE hthread;
9863 DWORD tid, qstatus;
9864 UINT qs_all_input = QS_ALLINPUT;
9865 UINT qs_input = QS_INPUT;
9866 BOOL ret;
9867 struct peekmsg_info info;
9868
9869 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9870 100, 100, 200, 200, 0, 0, 0, NULL);
9871 assert(info.hwnd);
9872 ShowWindow(info.hwnd, SW_SHOW);
9873 UpdateWindow(info.hwnd);
9874 SetFocus(info.hwnd);
9875
9876 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9877 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9878 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9879
9880 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9881 WaitForSingleObject(info.hevent[EV_ACK], 10000);
9882
9883 flush_events();
9884 flush_sequence();
9885
9886 SetLastError(0xdeadbeef);
9887 qstatus = GetQueueStatus(qs_all_input);
9888 if (GetLastError() == ERROR_INVALID_FLAGS)
9889 {
9890 trace("QS_RAWINPUT not supported on this platform\n");
9891 qs_all_input &= ~QS_RAWINPUT;
9892 qs_input &= ~QS_RAWINPUT;
9893 }
9894 if (qstatus & QS_POSTMESSAGE)
9895 {
9896 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9897 qstatus = GetQueueStatus(qs_all_input);
9898 }
9899 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9900
9901 trace("signalling to send message\n");
9902 SetEvent(info.hevent[EV_SENDMSG]);
9903 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9904
9905 /* pass invalid QS_xxxx flags */
9906 SetLastError(0xdeadbeef);
9907 qstatus = GetQueueStatus(0xffffffff);
9908 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9909 if (!qstatus)
9910 {
9911 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9912 qstatus = GetQueueStatus(qs_all_input);
9913 }
9914 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
9915 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9916 "wrong qstatus %08x\n", qstatus);
9917
9918 msg.message = 0;
9919 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9920 ok(!ret,
9921 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9922 msg.message);
9923 ok_sequence(WmUser, "WmUser", FALSE);
9924
9925 qstatus = GetQueueStatus(qs_all_input);
9926 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9927
9928 keybd_event('N', 0, 0, 0);
9929 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9930 qstatus = GetQueueStatus(qs_all_input);
9931 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9932 {
9933 skip( "queuing key events not supported\n" );
9934 goto done;
9935 }
9936 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
9937 /* keybd_event seems to trigger a sent message on NT4 */
9938 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
9939 "wrong qstatus %08x\n", qstatus);
9940
9941 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9942 qstatus = GetQueueStatus(qs_all_input);
9943 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
9944 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9945 "wrong qstatus %08x\n", qstatus);
9946
9947 InvalidateRect(info.hwnd, NULL, FALSE);
9948 qstatus = GetQueueStatus(qs_all_input);
9949 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
9950 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9951 "wrong qstatus %08x\n", qstatus);
9952
9953 trace("signalling to send message\n");
9954 SetEvent(info.hevent[EV_SENDMSG]);
9955 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9956
9957 qstatus = GetQueueStatus(qs_all_input);
9958 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9959 "wrong qstatus %08x\n", qstatus);
9960
9961 msg.message = 0;
9962 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9963 if (ret && msg.message == WM_CHAR)
9964 {
9965 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9966 goto done;
9967 }
9968 ok(!ret,
9969 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9970 msg.message);
9971 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
9972 {
9973 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9974 goto done;
9975 }
9976 ok_sequence(WmUser, "WmUser", FALSE);
9977
9978 qstatus = GetQueueStatus(qs_all_input);
9979 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9980 "wrong qstatus %08x\n", qstatus);
9981
9982 trace("signalling to send message\n");
9983 SetEvent(info.hevent[EV_SENDMSG]);
9984 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9985
9986 qstatus = GetQueueStatus(qs_all_input);
9987 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9988 "wrong qstatus %08x\n", qstatus);
9989
9990 msg.message = 0;
9991 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9992 ok(!ret,
9993 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9994 msg.message);
9995 ok_sequence(WmUser, "WmUser", FALSE);
9996
9997 qstatus = GetQueueStatus(qs_all_input);
9998 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9999 "wrong qstatus %08x\n", qstatus);
10000
10001 msg.message = 0;
10002 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
10003 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10004 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10005 ret, msg.message, msg.wParam);
10006 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10007
10008 qstatus = GetQueueStatus(qs_all_input);
10009 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
10010 "wrong qstatus %08x\n", qstatus);
10011
10012 msg.message = 0;
10013 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
10014 ok(!ret,
10015 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10016 msg.message);
10017 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10018
10019 qstatus = GetQueueStatus(qs_all_input);
10020 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
10021 "wrong qstatus %08x\n", qstatus);
10022
10023 msg.message = 0;
10024 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
10025 ok(ret && msg.message == WM_PAINT,
10026 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
10027 DispatchMessageA(&msg);
10028 ok_sequence(WmPaint, "WmPaint", FALSE);
10029
10030 qstatus = GetQueueStatus(qs_all_input);
10031 ok(qstatus == MAKELONG(0, QS_KEY),
10032 "wrong qstatus %08x\n", qstatus);
10033
10034 msg.message = 0;
10035 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
10036 ok(!ret,
10037 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10038 msg.message);
10039 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10040
10041 qstatus = GetQueueStatus(qs_all_input);
10042 ok(qstatus == MAKELONG(0, QS_KEY),
10043 "wrong qstatus %08x\n", qstatus);
10044
10045 trace("signalling to send message\n");
10046 SetEvent(info.hevent[EV_SENDMSG]);
10047 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10048
10049 qstatus = GetQueueStatus(qs_all_input);
10050 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
10051 "wrong qstatus %08x\n", qstatus);
10052
10053 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10054
10055 qstatus = GetQueueStatus(qs_all_input);
10056 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
10057 "wrong qstatus %08x\n", qstatus);
10058
10059 msg.message = 0;
10060 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
10061 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10062 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10063 ret, msg.message, msg.wParam);
10064 ok_sequence(WmUser, "WmUser", FALSE);
10065
10066 qstatus = GetQueueStatus(qs_all_input);
10067 ok(qstatus == MAKELONG(0, QS_KEY),
10068 "wrong qstatus %08x\n", qstatus);
10069
10070 msg.message = 0;
10071 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
10072 ok(!ret,
10073 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10074 msg.message);
10075 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10076
10077 qstatus = GetQueueStatus(qs_all_input);
10078 ok(qstatus == MAKELONG(0, QS_KEY),
10079 "wrong qstatus %08x\n", qstatus);
10080
10081 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10082
10083 qstatus = GetQueueStatus(qs_all_input);
10084 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
10085 "wrong qstatus %08x\n", qstatus);
10086
10087 trace("signalling to send message\n");
10088 SetEvent(info.hevent[EV_SENDMSG]);
10089 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10090
10091 qstatus = GetQueueStatus(qs_all_input);
10092 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
10093 "wrong qstatus %08x\n", qstatus);
10094
10095 msg.message = 0;
10096 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
10097 ok(!ret,
10098 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10099 msg.message);
10100 ok_sequence(WmUser, "WmUser", FALSE);
10101
10102 qstatus = GetQueueStatus(qs_all_input);
10103 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
10104 "wrong qstatus %08x\n", qstatus);
10105
10106 msg.message = 0;
10107 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
10108 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
10109 else /* workaround for a missing QS_RAWINPUT support */
10110 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
10111 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10112 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10113 ret, msg.message, msg.wParam);
10114 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
10115
10116 qstatus = GetQueueStatus(qs_all_input);
10117 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
10118 "wrong qstatus %08x\n", qstatus);
10119
10120 msg.message = 0;
10121 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
10122 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
10123 else /* workaround for a missing QS_RAWINPUT support */
10124 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
10125 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
10126 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
10127 ret, msg.message, msg.wParam);
10128 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
10129
10130 qstatus = GetQueueStatus(qs_all_input);
10131 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10132 "wrong qstatus %08x\n", qstatus);
10133
10134 msg.message = 0;
10135 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
10136 ok(!ret,
10137 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10138 msg.message);
10139 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10140
10141 qstatus = GetQueueStatus(qs_all_input);
10142 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10143 "wrong qstatus %08x\n", qstatus);
10144
10145 msg.message = 0;
10146 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10147 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10148 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10149 ret, msg.message, msg.wParam);
10150 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10151
10152 qstatus = GetQueueStatus(qs_all_input);
10153 ok(qstatus == 0,
10154 "wrong qstatus %08x\n", qstatus);
10155
10156 msg.message = 0;
10157 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10158 ok(!ret,
10159 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10160 msg.message);
10161 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10162
10163 qstatus = GetQueueStatus(qs_all_input);
10164 ok(qstatus == 0,
10165 "wrong qstatus %08x\n", qstatus);
10166
10167 /* test whether presence of the quit flag in the queue affects
10168 * the queue state
10169 */
10170 PostQuitMessage(0x1234abcd);
10171
10172 qstatus = GetQueueStatus(qs_all_input);
10173 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
10174 "wrong qstatus %08x\n", qstatus);
10175
10176 PostMessageA(info.hwnd, WM_USER, 0, 0);
10177
10178 qstatus = GetQueueStatus(qs_all_input);
10179 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
10180 "wrong qstatus %08x\n", qstatus);
10181
10182 msg.message = 0;
10183 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10184 ok(ret && msg.message == WM_USER,
10185 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
10186 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10187
10188 qstatus = GetQueueStatus(qs_all_input);
10189 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10190 "wrong qstatus %08x\n", qstatus);
10191
10192 msg.message = 0;
10193 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10194 ok(ret && msg.message == WM_QUIT,
10195 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
10196 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
10197 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
10198 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10199
10200 qstatus = GetQueueStatus(qs_all_input);
10201 todo_wine {
10202 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10203 "wrong qstatus %08x\n", qstatus);
10204 }
10205
10206 msg.message = 0;
10207 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10208 ok(!ret,
10209 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10210 msg.message);
10211 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10212
10213 qstatus = GetQueueStatus(qs_all_input);
10214 ok(qstatus == 0,
10215 "wrong qstatus %08x\n", qstatus);
10216
10217 /* some GetMessage tests */
10218
10219 keybd_event('N', 0, 0, 0);
10220 qstatus = GetQueueStatus(qs_all_input);
10221 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10222
10223 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10224 qstatus = GetQueueStatus(qs_all_input);
10225 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10226
10227 if (qstatus)
10228 {
10229 ret = GetMessageA( &msg, 0, 0, 0 );
10230 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10231 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10232 ret, msg.message, msg.wParam);
10233 qstatus = GetQueueStatus(qs_all_input);
10234 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
10235 }
10236
10237 if (qstatus)
10238 {
10239 ret = GetMessageA( &msg, 0, 0, 0 );
10240 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10241 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10242 ret, msg.message, msg.wParam);
10243 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
10244 qstatus = GetQueueStatus(qs_all_input);
10245 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10246 }
10247
10248 keybd_event('N', 0, 0, 0);
10249 qstatus = GetQueueStatus(qs_all_input);
10250 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10251
10252 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10253 qstatus = GetQueueStatus(qs_all_input);
10254 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10255
10256 if (qstatus & (QS_KEY << 16))
10257 {
10258 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
10259 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10260 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10261 ret, msg.message, msg.wParam);
10262 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
10263 qstatus = GetQueueStatus(qs_all_input);
10264 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
10265 }
10266
10267 if (qstatus)
10268 {
10269 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
10270 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10271 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10272 ret, msg.message, msg.wParam);
10273 qstatus = GetQueueStatus(qs_all_input);
10274 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10275 }
10276
10277 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10278 qstatus = GetQueueStatus(qs_all_input);
10279 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10280
10281 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10282 qstatus = GetQueueStatus(qs_all_input);
10283 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10284
10285 trace("signalling to send message\n");
10286 SetEvent(info.hevent[EV_SENDMSG]);
10287 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10288 qstatus = GetQueueStatus(qs_all_input);
10289 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
10290 "wrong qstatus %08x\n", qstatus);
10291
10292 if (qstatus & (QS_KEY << 16))
10293 {
10294 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
10295 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
10296 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10297 ret, msg.message, msg.wParam);
10298 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
10299 qstatus = GetQueueStatus(qs_all_input);
10300 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
10301 }
10302
10303 if (qstatus)
10304 {
10305 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
10306 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10307 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10308 ret, msg.message, msg.wParam);
10309 qstatus = GetQueueStatus(qs_all_input);
10310 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10311 }
10312 done:
10313 trace("signalling to exit\n");
10314 SetEvent(info.hevent[EV_STOP]);
10315
10316 WaitForSingleObject(hthread, INFINITE);
10317
10318 CloseHandle(hthread);
10319 CloseHandle(info.hevent[0]);
10320 CloseHandle(info.hevent[1]);
10321 CloseHandle(info.hevent[2]);
10322
10323 DestroyWindow(info.hwnd);
10324 }
10325
10326 static void wait_move_event(HWND hwnd, int x, int y)
10327 {
10328 MSG msg;
10329 DWORD time;
10330 BOOL ret, go = FALSE;
10331
10332 time = GetTickCount();
10333 while (GetTickCount() - time < 200 && !go) {
10334 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10335 go = ret && msg.pt.x > x && msg.pt.y > y;
10336 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
10337 }
10338 }
10339
10340 #define STEP 5
10341 static void test_PeekMessage2(void)
10342 {
10343 HWND hwnd;
10344 BOOL ret;
10345 MSG msg;
10346 UINT message;
10347 DWORD time1, time2, time3;
10348 int x1, y1, x2, y2, x3, y3;
10349 POINT pos;
10350
10351 time1 = time2 = time3 = 0;
10352 x1 = y1 = x2 = y2 = x3 = y3 = 0;
10353
10354 /* Initialise window and make sure it is ready for events */
10355 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
10356 10, 10, 800, 800, NULL, NULL, NULL, NULL);
10357 assert(hwnd);
10358 trace("Window for test_PeekMessage2 %p\n", hwnd);
10359 ShowWindow(hwnd, SW_SHOW);
10360 UpdateWindow(hwnd);
10361 SetFocus(hwnd);
10362 GetCursorPos(&pos);
10363 SetCursorPos(100, 100);
10364 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
10365 flush_events();
10366
10367 /* Do initial mousemove, wait until we can see it
10368 and then do our test peek with PM_NOREMOVE. */
10369 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10370 wait_move_event(hwnd, 100-STEP, 100-STEP);
10371
10372 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10373 if (!ret)
10374 {
10375 skip( "queuing mouse events not supported\n" );
10376 goto done;
10377 }
10378 else
10379 {
10380 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10381 message = msg.message;
10382 time1 = msg.time;
10383 x1 = msg.pt.x;
10384 y1 = msg.pt.y;
10385 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10386 }
10387
10388 /* Allow time to advance a bit, and then simulate the user moving their
10389 * mouse around. After that we peek again with PM_NOREMOVE.
10390 * Although the previous mousemove message was never removed, the
10391 * mousemove we now peek should reflect the recent mouse movements
10392 * because the input queue will merge the move events. */
10393 Sleep(100);
10394 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10395 wait_move_event(hwnd, x1, y1);
10396
10397 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10398 ok(ret, "no message available\n");
10399 if (ret) {
10400 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10401 message = msg.message;
10402 time2 = msg.time;
10403 x2 = msg.pt.x;
10404 y2 = msg.pt.y;
10405 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10406 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
10407 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
10408 }
10409
10410 /* Have another go, to drive the point home */
10411 Sleep(100);
10412 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10413 wait_move_event(hwnd, x2, y2);
10414
10415 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10416 ok(ret, "no message available\n");
10417 if (ret) {
10418 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10419 message = msg.message;
10420 time3 = msg.time;
10421 x3 = msg.pt.x;
10422 y3 = msg.pt.y;
10423 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10424 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
10425 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
10426 }
10427
10428 done:
10429 DestroyWindow(hwnd);
10430 SetCursorPos(pos.x, pos.y);
10431 flush_events();
10432 }
10433
10434 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10435 {
10436 struct recvd_message msg;
10437
10438 if (ignore_message( message )) return 0;
10439
10440 msg.hwnd = hwnd;
10441 msg.message = message;
10442 msg.flags = sent|wparam|lparam;
10443 msg.wParam = wp;
10444 msg.lParam = lp;
10445 msg.descr = "dialog";
10446 add_message(&msg);
10447
10448 switch (message)
10449 {
10450 case WM_INITDIALOG:
10451 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
10452 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
10453 return 0;
10454
10455 case WM_GETDLGCODE:
10456 return 0;
10457
10458 case WM_USER:
10459 EndDialog(hwnd, 0);
10460 break;
10461 }
10462
10463 return 1;
10464 }
10465
10466 static const struct message WmQuitDialogSeq[] = {
10467 { HCBT_CREATEWND, hook },
10468 { WM_SETFONT, sent },
10469 { WM_INITDIALOG, sent },
10470 { WM_CHANGEUISTATE, sent|optional },
10471 { HCBT_DESTROYWND, hook },
10472 { 0x0090, sent|optional }, /* Vista */
10473 { WM_DESTROY, sent },
10474 { WM_NCDESTROY, sent },
10475 { 0 }
10476 };
10477
10478 static const struct message WmStopQuitSeq[] = {
10479 { WM_DWMNCRENDERINGCHANGED, posted|optional },
10480 { WM_CLOSE, posted },
10481 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
10482 { 0 }
10483 };
10484
10485 static void test_quit_message(void)
10486 {
10487 MSG msg;
10488 BOOL ret;
10489
10490 /* test using PostQuitMessage */
10491 flush_events();
10492 PostQuitMessage(0xbeef);
10493
10494 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
10495 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10496 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10497 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10498
10499 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
10500 ok(ret, "PostMessage failed with error %d\n", GetLastError());
10501
10502 ret = GetMessageA(&msg, NULL, 0, 0);
10503 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10504 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10505
10506 /* note: WM_QUIT message received after WM_USER message */
10507 ret = GetMessageA(&msg, NULL, 0, 0);
10508 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10509 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10510 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10511
10512 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
10513 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
10514
10515 /* now test with PostThreadMessage - different behaviour! */
10516 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
10517
10518 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
10519 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10520 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10521 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10522
10523 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
10524 ok(ret, "PostMessage failed with error %d\n", GetLastError());
10525
10526 /* note: we receive the WM_QUIT message first this time */
10527 ret = GetMessageA(&msg, NULL, 0, 0);
10528 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10529 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10530 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10531
10532 ret = GetMessageA(&msg, NULL, 0, 0);
10533 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10534 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10535
10536 flush_events();
10537 flush_sequence();
10538 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
10539 ok(ret == 1, "expected 1, got %d\n", ret);
10540 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
10541 memset(&msg, 0xab, sizeof(msg));
10542 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
10543 ok(ret, "PeekMessage failed\n");
10544 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10545 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
10546 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
10547
10548 /* Check what happens to a WM_QUIT message posted to a window that gets
10549 * destroyed.
10550 */
10551 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
10552 0, 0, 100, 100, NULL, NULL, NULL, NULL);
10553 flush_sequence();
10554 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10555 {
10556 struct recvd_message rmsg;
10557 rmsg.hwnd = msg.hwnd;
10558 rmsg.message = msg.message;
10559 rmsg.flags = posted|wparam|lparam;
10560 rmsg.wParam = msg.wParam;
10561 rmsg.lParam = msg.lParam;
10562 rmsg.descr = "stop/quit";
10563 if (msg.message == WM_QUIT)
10564 /* The hwnd can only be checked here */
10565 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
10566 add_message(&rmsg);
10567 DispatchMessageA(&msg);
10568 }
10569 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
10570 }
10571
10572 static const struct message WmMouseHoverSeq[] = {
10573 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
10574 { WM_MOUSEACTIVATE, sent|optional },
10575 { WM_TIMER, sent|optional }, /* XP sends it */
10576 { WM_SYSTIMER, sent },
10577 { WM_MOUSEHOVER, sent|wparam, 0 },
10578 { 0 }
10579 };
10580
10581 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
10582 {
10583 MSG msg;
10584 DWORD start_ticks, end_ticks;
10585
10586 start_ticks = GetTickCount();
10587 /* add some deviation (50%) to cover not expected delays */
10588 start_ticks += timeout / 2;
10589
10590 do
10591 {
10592 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10593 {
10594 /* Timer proc messages are not dispatched to the window proc,
10595 * and therefore not logged.
10596 */
10597 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
10598 {
10599 struct recvd_message s_msg;
10600
10601 s_msg.hwnd = msg.hwnd;
10602 s_msg.message = msg.message;
10603 s_msg.flags = sent|wparam|lparam;
10604 s_msg.wParam = msg.wParam;
10605 s_msg.lParam = msg.lParam;
10606 s_msg.descr = "msg_loop";
10607 add_message(&s_msg);
10608 }
10609 DispatchMessageA(&msg);
10610 }
10611
10612 end_ticks = GetTickCount();
10613
10614 /* inject WM_MOUSEMOVE to see how it changes tracking */
10615 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
10616 {
10617 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10618 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10619
10620 inject_mouse_move = FALSE;
10621 }
10622 } while (start_ticks + timeout >= end_ticks);
10623 }
10624
10625 static void test_TrackMouseEvent(void)
10626 {
10627 TRACKMOUSEEVENT tme;
10628 BOOL ret;
10629 HWND hwnd, hchild;
10630 RECT rc_parent, rc_child;
10631 UINT default_hover_time, hover_width = 0, hover_height = 0;
10632
10633 #define track_hover(track_hwnd, track_hover_time) \
10634 tme.cbSize = sizeof(tme); \
10635 tme.dwFlags = TME_HOVER; \
10636 tme.hwndTrack = track_hwnd; \
10637 tme.dwHoverTime = track_hover_time; \
10638 SetLastError(0xdeadbeef); \
10639 ret = pTrackMouseEvent(&tme); \
10640 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
10641
10642 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
10643 tme.cbSize = sizeof(tme); \
10644 tme.dwFlags = TME_QUERY; \
10645 tme.hwndTrack = (HWND)0xdeadbeef; \
10646 tme.dwHoverTime = 0xdeadbeef; \
10647 SetLastError(0xdeadbeef); \
10648 ret = pTrackMouseEvent(&tme); \
10649 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
10650 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
10651 ok(tme.dwFlags == (expected_track_flags), \
10652 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
10653 ok(tme.hwndTrack == (expected_track_hwnd), \
10654 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
10655 ok(tme.dwHoverTime == (expected_hover_time), \
10656 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
10657
10658 #define track_hover_cancel(track_hwnd) \
10659 tme.cbSize = sizeof(tme); \
10660 tme.dwFlags = TME_HOVER | TME_CANCEL; \
10661 tme.hwndTrack = track_hwnd; \
10662 tme.dwHoverTime = 0xdeadbeef; \
10663 SetLastError(0xdeadbeef); \
10664 ret = pTrackMouseEvent(&tme); \
10665 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
10666
10667 default_hover_time = 0xdeadbeef;
10668 SetLastError(0xdeadbeef);
10669 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
10670 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10671 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
10672 if (!ret) default_hover_time = 400;
10673 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
10674
10675 SetLastError(0xdeadbeef);
10676 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
10677 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10678 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
10679 if (!ret) hover_width = 4;
10680 SetLastError(0xdeadbeef);
10681 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
10682 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10683 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
10684 if (!ret) hover_height = 4;
10685 trace("hover rect is %u x %d\n", hover_width, hover_height);
10686
10687 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10688 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10689 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10690 NULL, NULL, 0);
10691 assert(hwnd);
10692
10693 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
10694 WS_CHILD | WS_BORDER | WS_VISIBLE,
10695 50, 50, 200, 200, hwnd,
10696 NULL, NULL, 0);
10697 assert(hchild);
10698
10699 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
10700 flush_events();
10701 flush_sequence();
10702
10703 tme.cbSize = 0;
10704 tme.dwFlags = TME_QUERY;
10705 tme.hwndTrack = (HWND)0xdeadbeef;
10706 tme.dwHoverTime = 0xdeadbeef;
10707 SetLastError(0xdeadbeef);
10708 ret = pTrackMouseEvent(&tme);
10709 ok(!ret, "TrackMouseEvent should fail\n");
10710 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
10711 "not expected error %u\n", GetLastError());
10712
10713 tme.cbSize = sizeof(tme);
10714 tme.dwFlags = TME_HOVER;
10715 tme.hwndTrack = (HWND)0xdeadbeef;
10716 tme.dwHoverTime = 0xdeadbeef;
10717 SetLastError(0xdeadbeef);
10718 ret = pTrackMouseEvent(&tme);
10719 ok(!ret, "TrackMouseEvent should fail\n");
10720 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10721 "not expected error %u\n", GetLastError());
10722
10723 tme.cbSize = sizeof(tme);
10724 tme.dwFlags = TME_HOVER | TME_CANCEL;
10725 tme.hwndTrack = (HWND)0xdeadbeef;
10726 tme.dwHoverTime = 0xdeadbeef;
10727 SetLastError(0xdeadbeef);
10728 ret = pTrackMouseEvent(&tme);
10729 ok(!ret, "TrackMouseEvent should fail\n");
10730 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10731 "not expected error %u\n", GetLastError());
10732
10733 GetWindowRect(hwnd, &rc_parent);
10734 GetWindowRect(hchild, &rc_child);
10735 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
10736
10737 /* Process messages so that the system updates its internal current
10738 * window and hittest, otherwise TrackMouseEvent calls don't have any
10739 * effect.
10740 */
10741 flush_events();
10742 flush_sequence();
10743
10744 track_query(0, NULL, 0);
10745 track_hover(hchild, 0);
10746 track_query(0, NULL, 0);
10747
10748 flush_events();
10749 flush_sequence();
10750
10751 track_hover(hwnd, 0);
10752 tme.cbSize = sizeof(tme);
10753 tme.dwFlags = TME_QUERY;
10754 tme.hwndTrack = (HWND)0xdeadbeef;
10755 tme.dwHoverTime = 0xdeadbeef;
10756 SetLastError(0xdeadbeef);
10757 ret = pTrackMouseEvent(&tme);
10758 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10759 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10760 if (!tme.dwFlags)
10761 {
10762 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10763 DestroyWindow( hwnd );
10764 return;
10765 }
10766 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10767 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10768 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10769 tme.dwHoverTime, default_hover_time);
10770
10771 pump_msg_loop_timeout(default_hover_time, FALSE);
10772 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10773
10774 track_query(0, NULL, 0);
10775
10776 track_hover(hwnd, HOVER_DEFAULT);
10777 track_query(TME_HOVER, hwnd, default_hover_time);
10778
10779 Sleep(default_hover_time / 2);
10780 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10781 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10782
10783 track_query(TME_HOVER, hwnd, default_hover_time);
10784
10785 pump_msg_loop_timeout(default_hover_time, FALSE);
10786 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10787
10788 track_query(0, NULL, 0);
10789
10790 track_hover(hwnd, HOVER_DEFAULT);
10791 track_query(TME_HOVER, hwnd, default_hover_time);
10792
10793 pump_msg_loop_timeout(default_hover_time, TRUE);
10794 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10795
10796 track_query(0, NULL, 0);
10797
10798 track_hover(hwnd, HOVER_DEFAULT);
10799 track_query(TME_HOVER, hwnd, default_hover_time);
10800 track_hover_cancel(hwnd);
10801
10802 DestroyWindow(hwnd);
10803
10804 #undef track_hover
10805 #undef track_query
10806 #undef track_hover_cancel
10807 }
10808
10809
10810 static const struct message WmSetWindowRgn[] = {
10811 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10812 { WM_NCCALCSIZE, sent|wparam, 1 },
10813 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10814 { WM_GETTEXT, sent|defwinproc|optional },
10815 { WM_ERASEBKGND, sent|optional },
10816 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10817 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10818 { 0 }
10819 };
10820
10821 static const struct message WmSetWindowRgn_no_redraw[] = {
10822 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10823 { WM_NCCALCSIZE, sent|wparam, 1 },
10824 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10825 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10826 { 0 }
10827 };
10828
10829 static const struct message WmSetWindowRgn_clear[] = {
10830 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10831 { WM_NCCALCSIZE, sent|wparam, 1 },
10832 { WM_NCPAINT, sent|optional },
10833 { WM_GETTEXT, sent|defwinproc|optional },
10834 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10835 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10836 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10837 { WM_NCPAINT, sent|optional },
10838 { WM_GETTEXT, sent|defwinproc|optional },
10839 { WM_ERASEBKGND, sent|optional },
10840 { WM_WINDOWPOSCHANGING, sent|optional },
10841 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10842 { WM_NCPAINT, sent|optional },
10843 { WM_GETTEXT, sent|defwinproc|optional },
10844 { WM_ERASEBKGND, sent|optional },
10845 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10846 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10847 { WM_NCPAINT, sent|optional },
10848 { WM_GETTEXT, sent|defwinproc|optional },
10849 { WM_ERASEBKGND, sent|optional },
10850 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10851 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10852 { 0 }
10853 };
10854
10855 static void test_SetWindowRgn(void)
10856 {
10857 HRGN hrgn;
10858 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10859 100, 100, 200, 200, 0, 0, 0, NULL);
10860 ok( hwnd != 0, "Failed to create overlapped window\n" );
10861
10862 ShowWindow( hwnd, SW_SHOW );
10863 UpdateWindow( hwnd );
10864 flush_events();
10865 flush_sequence();
10866
10867 trace("testing SetWindowRgn\n");
10868 hrgn = CreateRectRgn( 0, 0, 150, 150 );
10869 SetWindowRgn( hwnd, hrgn, TRUE );
10870 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10871
10872 hrgn = CreateRectRgn( 30, 30, 160, 160 );
10873 SetWindowRgn( hwnd, hrgn, FALSE );
10874 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10875
10876 hrgn = CreateRectRgn( 0, 0, 180, 180 );
10877 SetWindowRgn( hwnd, hrgn, TRUE );
10878 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10879
10880 SetWindowRgn( hwnd, 0, TRUE );
10881 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10882
10883 DestroyWindow( hwnd );
10884 }
10885
10886 /*************************** ShowWindow() test ******************************/
10887 static const struct message WmShowNormal[] = {
10888 { WM_SHOWWINDOW, sent|wparam, 1 },
10889 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10890 { HCBT_ACTIVATE, hook },
10891 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10892 { HCBT_SETFOCUS, hook },
10893 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10894 { 0 }
10895 };
10896 static const struct message WmShow[] = {
10897 { WM_SHOWWINDOW, sent|wparam, 1 },
10898 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10899 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10900 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10901 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10902 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10903 { 0 }
10904 };
10905 static const struct message WmShowNoActivate_1[] = {
10906 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10907 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10908 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10909 { WM_MOVE, sent|defwinproc|optional },
10910 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10911 { 0 }
10912 };
10913 static const struct message WmShowNoActivate_2[] = {
10914 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10915 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
10916 { HCBT_ACTIVATE, hook|optional },
10917 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10918 { HCBT_SETFOCUS, hook|optional },
10919 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
10920 { WM_MOVE, sent|defwinproc },
10921 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10922 { HCBT_SETFOCUS, hook|optional },
10923 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10924 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10925 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10926 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10927 { 0 }
10928 };
10929 static const struct message WmShowNA_1[] = {
10930 { WM_SHOWWINDOW, sent|wparam, 1 },
10931 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10932 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10933 { 0 }
10934 };
10935 static const struct message WmShowNA_2[] = {
10936 { WM_SHOWWINDOW, sent|wparam, 1 },
10937 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10938 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10939 { 0 }
10940 };
10941 static const struct message WmRestore_1[] = {
10942 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10943 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10944 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10945 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10946 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10947 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10948 { WM_MOVE, sent|defwinproc },
10949 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10950 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10951 { 0 }
10952 };
10953 static const struct message WmRestore_2[] = {
10954 { WM_SHOWWINDOW, sent|wparam, 1 },
10955 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10956 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10957 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10958 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10959 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10960 { 0 }
10961 };
10962 static const struct message WmRestore_3[] = {
10963 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10964 { WM_GETMINMAXINFO, sent },
10965 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10966 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10967 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10968 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10969 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10970 { WM_MOVE, sent|defwinproc },
10971 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10972 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10973 { 0 }
10974 };
10975 static const struct message WmRestore_4[] = {
10976 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10977 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10978 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10979 { WM_MOVE, sent|defwinproc|optional },
10980 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10981 { 0 }
10982 };
10983 static const struct message WmRestore_5[] = {
10984 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10985 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10986 { HCBT_ACTIVATE, hook|optional },
10987 { HCBT_SETFOCUS, hook|optional },
10988 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10989 { WM_MOVE, sent|defwinproc|optional },
10990 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10991 { 0 }
10992 };
10993 static const struct message WmHide_1[] = {
10994 { WM_SHOWWINDOW, sent|wparam, 0 },
10995 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
10996 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
10997 { HCBT_ACTIVATE, hook|optional },
10998 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10999 { 0 }
11000 };
11001 static const struct message WmHide_2[] = {
11002 { WM_SHOWWINDOW, sent|wparam, 0 },
11003 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
11004 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
11005 { HCBT_ACTIVATE, hook|optional },
11006 { 0 }
11007 };
11008 static const struct message WmHide_3[] = {
11009 { WM_SHOWWINDOW, sent|wparam, 0 },
11010 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
11011 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11012 { HCBT_SETFOCUS, hook|optional },
11013 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11014 { 0 }
11015 };
11016 static const struct message WmShowMinimized_1[] = {
11017 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
11018 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11019 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
11020 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
11021 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11022 { WM_MOVE, sent|defwinproc },
11023 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
11024 { 0 }
11025 };
11026 static const struct message WmMinimize_1[] = {
11027 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
11028 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
11029 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11030 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11031 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11032 { WM_MOVE, sent|defwinproc },
11033 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
11034 { 0 }
11035 };
11036 static const struct message WmMinimize_2[] = {
11037 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
11038 { HCBT_SETFOCUS, hook|optional },
11039 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
11040 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
11041 { WM_MOVE, sent|defwinproc },
11042 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
11043 { 0 }
11044 };
11045 static const struct message WmMinimize_3[] = {
11046 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
11047 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
11048 { HCBT_ACTIVATE, hook|optional },
11049 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11050 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
11051 { WM_MOVE, sent|defwinproc },
11052 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
11053 { 0 }
11054 };
11055 static const struct message WmShowMinNoActivate[] = {
11056 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
11057 { WM_WINDOWPOSCHANGING, sent },
11058 { WM_WINDOWPOSCHANGED, sent },
11059 { WM_MOVE, sent|defwinproc|optional },
11060 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
11061 { 0 }
11062 };
11063 static const struct message WmMinMax_1[] = {
11064 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
11065 { 0 }
11066 };
11067 static const struct message WmMinMax_2[] = {
11068 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11069 { WM_GETMINMAXINFO, sent|optional },
11070 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
11071 { HCBT_ACTIVATE, hook|optional },
11072 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11073 { HCBT_SETFOCUS, hook|optional },
11074 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11075 { WM_MOVE, sent|defwinproc|optional },
11076 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
11077 { HCBT_SETFOCUS, hook|optional },
11078 { 0 }
11079 };
11080 static const struct message WmMinMax_3[] = {
11081 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
11082 { HCBT_SETFOCUS, hook|optional },
11083 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11084 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11085 { WM_MOVE, sent|defwinproc|optional },
11086 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
11087 { 0 }
11088 };
11089 static const struct message WmMinMax_4[] = {
11090 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
11091 { 0 }
11092 };
11093 static const struct message WmShowMaximized_1[] = {
11094 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11095 { WM_GETMINMAXINFO, sent },
11096 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11097 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
11098 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
11099 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
11100 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11101 { WM_MOVE, sent|defwinproc },
11102 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11103 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
11104 { 0 }
11105 };
11106 static const struct message WmShowMaximized_2[] = {
11107 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11108 { WM_GETMINMAXINFO, sent },
11109 { WM_WINDOWPOSCHANGING, sent|optional },
11110 { HCBT_ACTIVATE, hook|optional },
11111 { WM_WINDOWPOSCHANGED, sent|optional },
11112 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
11113 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
11114 { WM_WINDOWPOSCHANGING, sent|optional },
11115 { HCBT_SETFOCUS, hook|optional },
11116 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11117 { WM_MOVE, sent|defwinproc },
11118 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11119 { HCBT_SETFOCUS, hook|optional },
11120 { 0 }
11121 };
11122 static const struct message WmShowMaximized_3[] = {
11123 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11124 { WM_GETMINMAXINFO, sent|optional },
11125 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
11126 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
11127 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
11128 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
11129 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
11130 { WM_MOVE, sent|defwinproc|optional },
11131 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11132 { 0 }
11133 };
11134
11135 static void test_ShowWindow(void)
11136 {
11137 /* ShowWindow commands in random order */
11138 static const struct
11139 {
11140 INT cmd; /* ShowWindow command */
11141 LPARAM ret; /* ShowWindow return value */
11142 DWORD style; /* window style after the command */
11143 const struct message *msg; /* message sequence the command produces */
11144 INT wp_cmd, wp_flags; /* window placement after the command */
11145 POINT wp_min, wp_max; /* window placement after the command */
11146 BOOL todo_msg; /* message sequence doesn't match what Wine does */
11147 } sw[] =
11148 {
11149 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
11150 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11151 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
11152 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11153 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
11154 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11155 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11156 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11157 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
11158 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11159 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
11160 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11161 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
11162 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11163 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11164 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11165 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
11166 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11167 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
11168 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11169 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
11170 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11171 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
11172 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11173 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
11174 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11175 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
11176 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11177 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
11178 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11179 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11180 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11181 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
11182 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11183 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
11184 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11185 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
11186 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11187 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11188 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11189 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11190 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11191 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
11192 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
11193 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
11194 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11195 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11196 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11197 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11198 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11199 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
11200 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11201 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
11202 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11203 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11204 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11205 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11206 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11207 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
11208 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11209 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
11210 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11211 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
11212 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11213 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11214 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11215 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
11216 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11217 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
11218 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11219 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11220 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11221 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
11222 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11223 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
11224 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11225 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
11226 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11227 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
11228 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11229 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11230 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11231 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
11232 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11233 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
11234 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11235 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
11236 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11237 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11238 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11239 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
11240 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11241 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
11242 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11243 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
11244 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11245 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
11246 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11247 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
11248 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11249 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
11250 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11251 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
11252 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11253 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11254 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11255 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
11256 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11257 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11258 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11259 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
11260 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11261 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
11262 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
11263 };
11264 HWND hwnd;
11265 DWORD style;
11266 LPARAM ret;
11267 INT i;
11268 WINDOWPLACEMENT wp;
11269 RECT win_rc, work_rc = {0, 0, 0, 0};
11270
11271 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
11272 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
11273 120, 120, 90, 90,
11274 0, 0, 0, NULL);
11275 assert(hwnd);
11276
11277 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
11278 ok(style == 0, "expected style 0, got %08x\n", style);
11279
11280 flush_events();
11281 flush_sequence();
11282
11283 if (pGetMonitorInfoA && pMonitorFromPoint)
11284 {
11285 HMONITOR hmon;
11286 MONITORINFO mi;
11287 POINT pt = {0, 0};
11288
11289 SetLastError(0xdeadbeef);
11290 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
11291 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
11292
11293 mi.cbSize = sizeof(mi);
11294 SetLastError(0xdeadbeef);
11295 ret = pGetMonitorInfoA(hmon, &mi);
11296 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
11297 trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n",
11298 mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom,
11299 mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
11300 work_rc = mi.rcWork;
11301 }
11302
11303 GetWindowRect(hwnd, &win_rc);
11304 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
11305
11306 wp.length = sizeof(wp);
11307 SetLastError(0xdeadbeaf);
11308 ret = GetWindowPlacement(hwnd, &wp);
11309 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11310 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
11311 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
11312 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
11313 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
11314 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
11315 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11316 if (work_rc.left || work_rc.top) todo_wine /* FIXME: remove once Wine is fixed */
11317 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11318 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11319 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11320 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11321 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11322 else
11323 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11324 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11325 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11326 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11327 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11328
11329 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
11330 {
11331 static const char * const sw_cmd_name[13] =
11332 {
11333 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
11334 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
11335 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
11336 "SW_NORMALNA" /* 0xCC */
11337 };
11338 char comment[64];
11339 INT idx; /* index into the above array of names */
11340
11341 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
11342
11343 style = GetWindowLongA(hwnd, GWL_STYLE);
11344 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
11345 ret = ShowWindow(hwnd, sw[i].cmd);
11346 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
11347 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
11348 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
11349
11350 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
11351 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
11352
11353 wp.length = sizeof(wp);
11354 SetLastError(0xdeadbeaf);
11355 ret = GetWindowPlacement(hwnd, &wp);
11356 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11357 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
11358 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
11359
11360 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
11361 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
11362 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
11363 {
11364 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
11365 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
11366 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11367 }
11368 else
11369 {
11370 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
11371 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11372 }
11373
11374 if (wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
11375 todo_wine
11376 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11377 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11378 else
11379 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11380 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11381
11382 if (0) /* FIXME: Wine behaves completely different here */
11383 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11384 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11385 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11386 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11387 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11388 }
11389 DestroyWindow(hwnd);
11390 flush_events();
11391 }
11392
11393 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11394 {
11395 struct recvd_message msg;
11396
11397 if (ignore_message( message )) return 0;
11398
11399 msg.hwnd = hwnd;
11400 msg.message = message;
11401 msg.flags = sent|wparam|lparam;
11402 msg.wParam = wParam;
11403 msg.lParam = lParam;
11404 msg.descr = "dialog";
11405 add_message(&msg);
11406
11407 /* calling DefDlgProc leads to a recursion under XP */
11408
11409 switch (message)
11410 {
11411 case WM_INITDIALOG:
11412 case WM_GETDLGCODE:
11413 return 0;
11414 }
11415 return 1;
11416 }
11417
11418 static const struct message WmDefDlgSetFocus_1[] = {
11419 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11420 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11421 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11422 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11423 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11424 { HCBT_SETFOCUS, hook },
11425 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11426 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11427 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11428 { WM_SETFOCUS, sent|wparam, 0 },
11429 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11430 { WM_CTLCOLOREDIT, sent },
11431 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11432 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11433 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11434 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11435 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
11436 { 0 }
11437 };
11438 static const struct message WmDefDlgSetFocus_2[] = {
11439 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11440 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11441 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11442 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11443 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11444 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11445 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
11446 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11447 { 0 }
11448 };
11449 /* Creation of a dialog */
11450 static const struct message WmCreateDialogParamSeq_1[] = {
11451 { HCBT_CREATEWND, hook },
11452 { WM_NCCREATE, sent },
11453 { WM_NCCALCSIZE, sent|wparam, 0 },
11454 { WM_CREATE, sent },
11455 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11456 { WM_SIZE, sent|wparam, SIZE_RESTORED },
11457 { WM_MOVE, sent },
11458 { WM_SETFONT, sent },
11459 { WM_INITDIALOG, sent },
11460 { WM_CHANGEUISTATE, sent|optional },
11461 { 0 }
11462 };
11463 /* Creation of a dialog */
11464 static const struct message WmCreateDialogParamSeq_2[] = {
11465 { HCBT_CREATEWND, hook },
11466 { WM_NCCREATE, sent },
11467 { WM_NCCALCSIZE, sent|wparam, 0 },
11468 { WM_CREATE, sent },
11469 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11470 { WM_SIZE, sent|wparam, SIZE_RESTORED },
11471 { WM_MOVE, sent },
11472 { WM_CHANGEUISTATE, sent|optional },
11473 { 0 }
11474 };
11475
11476 static void test_dialog_messages(void)
11477 {
11478 WNDCLASSA cls;
11479 HWND hdlg, hedit1, hedit2, hfocus;
11480 LRESULT ret;
11481
11482 #define set_selection(hctl, start, end) \
11483 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
11484 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
11485
11486 #define check_selection(hctl, start, end) \
11487 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
11488 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
11489
11490 subclass_edit();
11491
11492 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
11493 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
11494 0, 0, 100, 100, 0, 0, 0, NULL);
11495 ok(hdlg != 0, "Failed to create custom dialog window\n");
11496
11497 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
11498 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11499 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
11500 ok(hedit1 != 0, "Failed to create edit control\n");
11501 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
11502 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11503 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
11504 ok(hedit2 != 0, "Failed to create edit control\n");
11505
11506 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
11507 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
11508
11509 hfocus = GetFocus();
11510 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
11511
11512 SetFocus(hedit2);
11513 hfocus = GetFocus();
11514 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
11515
11516 check_selection(hedit1, 0, 0);
11517 check_selection(hedit2, 0, 0);
11518
11519 set_selection(hedit2, 0, -1);
11520 check_selection(hedit2, 0, 3);
11521
11522 SetFocus(0);
11523 hfocus = GetFocus();
11524 ok(hfocus == 0, "wrong focus %p\n", hfocus);
11525
11526 flush_sequence();
11527 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
11528 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11529 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
11530
11531 hfocus = GetFocus();
11532 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11533
11534 check_selection(hedit1, 0, 5);
11535 check_selection(hedit2, 0, 3);
11536
11537 flush_sequence();
11538 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
11539 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11540 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
11541
11542 hfocus = GetFocus();
11543 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11544
11545 check_selection(hedit1, 0, 5);
11546 check_selection(hedit2, 0, 3);
11547
11548 EndDialog(hdlg, 0);
11549 DestroyWindow(hedit1);
11550 DestroyWindow(hedit2);
11551 DestroyWindow(hdlg);
11552 flush_sequence();
11553
11554 #undef set_selection
11555 #undef check_selection
11556
11557 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11558 cls.lpszClassName = "MyDialogClass";
11559 cls.hInstance = GetModuleHandleA(NULL);
11560 /* need a cast since a dlgproc is used as a wndproc */
11561 cls.lpfnWndProc = test_dlg_proc;
11562 if (!RegisterClassA(&cls)) assert(0);
11563
11564 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
11565 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11566 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
11567 EndDialog(hdlg, 0);
11568 DestroyWindow(hdlg);
11569 flush_sequence();
11570
11571 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
11572 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11573 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
11574 EndDialog(hdlg, 0);
11575 DestroyWindow(hdlg);
11576 flush_sequence();
11577
11578 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11579 }
11580
11581 static void test_EndDialog(void)
11582 {
11583 HWND hparent, hother, hactive, hdlg;
11584 WNDCLASSA cls;
11585
11586 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
11587 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
11588 100, 100, 200, 200, 0, 0, 0, NULL);
11589 ok (hparent != 0, "Failed to create parent window\n");
11590
11591 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
11592 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11593 100, 100, 200, 200, 0, 0, 0, NULL);
11594 ok (hother != 0, "Failed to create parent window\n");
11595
11596 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11597 cls.lpszClassName = "MyDialogClass";
11598 cls.hInstance = GetModuleHandleA(NULL);
11599 cls.lpfnWndProc = test_dlg_proc;
11600 if (!RegisterClassA(&cls)) assert(0);
11601
11602 flush_sequence();
11603 SetForegroundWindow(hother);
11604 hactive = GetForegroundWindow();
11605 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
11606
11607 /* create a dialog where the parent is disabled, this parent should still
11608 receive the focus when the dialog exits (even though "normally" a
11609 disabled window should not receive the focus) */
11610 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
11611 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11612 SetForegroundWindow(hdlg);
11613 hactive = GetForegroundWindow();
11614 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
11615 EndDialog(hdlg, 0);
11616 hactive = GetForegroundWindow();
11617 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
11618 DestroyWindow(hdlg);
11619 flush_sequence();
11620
11621 DestroyWindow( hother );
11622 DestroyWindow( hparent );
11623 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11624 }
11625
11626 static void test_nullCallback(void)
11627 {
11628 HWND hwnd;
11629
11630 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
11631 100, 100, 200, 200, 0, 0, 0, NULL);
11632 ok (hwnd != 0, "Failed to create overlapped window\n");
11633
11634 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
11635 flush_events();
11636 DestroyWindow(hwnd);
11637 }
11638
11639 /* SetActiveWindow( 0 ) hwnd visible */
11640 static const struct message SetActiveWindowSeq0[] =
11641 {
11642 { HCBT_ACTIVATE, hook|optional },
11643 { WM_NCACTIVATE, sent|wparam, 0 },
11644 { WM_GETTEXT, sent|defwinproc|optional },
11645 { WM_ACTIVATE, sent|wparam, 0 },
11646 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11647 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11648 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11649 { WM_KILLFOCUS, sent|optional },
11650 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11651 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11652 { WM_NCACTIVATE, sent|wparam|optional, 1 },
11653 { WM_GETTEXT, sent|defwinproc|optional },
11654 { WM_ACTIVATE, sent|wparam|optional, 1 },
11655 { HCBT_SETFOCUS, hook|optional },
11656 { WM_KILLFOCUS, sent|defwinproc|optional },
11657 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11658 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11659 { WM_IME_SETCONTEXT, sent|optional },
11660 { WM_IME_SETCONTEXT, sent|optional },
11661 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11662 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11663 { WM_SETFOCUS, sent|defwinproc|optional },
11664 { WM_GETTEXT, sent|optional },
11665 { 0 }
11666 };
11667 /* SetActiveWindow( hwnd ) hwnd visible */
11668 static const struct message SetActiveWindowSeq1[] =
11669 {
11670 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11671 { 0 }
11672 };
11673 /* SetActiveWindow( popup ) hwnd visible, popup visible */
11674 static const struct message SetActiveWindowSeq2[] =
11675 {
11676 { HCBT_ACTIVATE, hook },
11677 { WM_NCACTIVATE, sent|wparam, 0 },
11678 { WM_GETTEXT, sent|defwinproc|optional },
11679 { WM_ACTIVATE, sent|wparam, 0 },
11680 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11681 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11682 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11683 { WM_NCPAINT, sent|optional },
11684 { WM_GETTEXT, sent|defwinproc|optional },
11685 { WM_ERASEBKGND, sent|optional },
11686 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11687 { WM_NCACTIVATE, sent|wparam, 1 },
11688 { WM_GETTEXT, sent|defwinproc|optional },
11689 { WM_ACTIVATE, sent|wparam, 1 },
11690 { HCBT_SETFOCUS, hook },
11691 { WM_KILLFOCUS, sent|defwinproc },
11692 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11693 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11694 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11695 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11696 { WM_SETFOCUS, sent|defwinproc },
11697 { WM_GETTEXT, sent|optional },
11698 { 0 }
11699 };
11700
11701 /* SetActiveWindow( hwnd ) hwnd not visible */
11702 static const struct message SetActiveWindowSeq3[] =
11703 {
11704 { HCBT_ACTIVATE, hook },
11705 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11706 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11707 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11708 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11709 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11710 { WM_ACTIVATEAPP, sent|wparam, 1 },
11711 { WM_ACTIVATEAPP, sent|wparam, 1 },
11712 { WM_NCACTIVATE, sent|wparam, 1 },
11713 { WM_ACTIVATE, sent|wparam, 1 },
11714 { HCBT_SETFOCUS, hook },
11715 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11716 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11717 { WM_SETFOCUS, sent|defwinproc },
11718 { 0 }
11719 };
11720 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
11721 static const struct message SetActiveWindowSeq4[] =
11722 {
11723 { HCBT_ACTIVATE, hook },
11724 { WM_NCACTIVATE, sent|wparam, 0 },
11725 { WM_GETTEXT, sent|defwinproc|optional },
11726 { WM_ACTIVATE, sent|wparam, 0 },
11727 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11728 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11729 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11730 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11731 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11732 { WM_NCACTIVATE, sent|wparam, 1 },
11733 { WM_GETTEXT, sent|defwinproc|optional },
11734 { WM_ACTIVATE, sent|wparam, 1 },
11735 { HCBT_SETFOCUS, hook },
11736 { WM_KILLFOCUS, sent|defwinproc },
11737 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11738 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11739 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11740 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11741 { WM_SETFOCUS, sent|defwinproc },
11742 { 0 }
11743 };
11744
11745
11746 static void test_SetActiveWindow(void)
11747 {
11748 HWND hwnd, popup, ret;
11749
11750 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11751 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11752 100, 100, 200, 200, 0, 0, 0, NULL);
11753
11754 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11755 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
11756 100, 100, 200, 200, hwnd, 0, 0, NULL);
11757
11758 ok(hwnd != 0, "Failed to create overlapped window\n");
11759 ok(popup != 0, "Failed to create popup window\n");
11760 SetForegroundWindow( popup );
11761 flush_sequence();
11762
11763 trace("SetActiveWindow(0)\n");
11764 ret = SetActiveWindow(0);
11765 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
11766 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
11767 flush_sequence();
11768
11769 trace("SetActiveWindow(hwnd), hwnd visible\n");
11770 ret = SetActiveWindow(hwnd);
11771 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
11772 flush_sequence();
11773
11774 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
11775 ret = SetActiveWindow(popup);
11776 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
11777 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
11778 flush_sequence();
11779
11780 ShowWindow(hwnd, SW_HIDE);
11781 ShowWindow(popup, SW_HIDE);
11782 flush_sequence();
11783
11784 trace("SetActiveWindow(hwnd), hwnd not visible\n");
11785 ret = SetActiveWindow(hwnd);
11786 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
11787 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
11788 flush_sequence();
11789
11790 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
11791 ret = SetActiveWindow(popup);
11792 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
11793 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
11794 flush_sequence();
11795
11796 trace("done\n");
11797
11798 DestroyWindow(hwnd);
11799 }
11800
11801 static const struct message SetForegroundWindowSeq[] =
11802 {
11803 { WM_NCACTIVATE, sent|wparam, 0 },
11804 { WM_GETTEXT, sent|defwinproc|optional },
11805 { WM_ACTIVATE, sent|wparam, 0 },
11806 { WM_ACTIVATEAPP, sent|wparam, 0 },
11807 { WM_KILLFOCUS, sent },
11808 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11809 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
11810 { 0 }
11811 };
11812
11813 static void test_SetForegroundWindow(void)
11814 {
11815 HWND hwnd;
11816
11817 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
11818 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11819 100, 100, 200, 200, 0, 0, 0, NULL);
11820 ok (hwnd != 0, "Failed to create overlapped window\n");
11821 SetForegroundWindow( hwnd );
11822 flush_sequence();
11823
11824 trace("SetForegroundWindow( 0 )\n");
11825 SetForegroundWindow( 0 );
11826 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
11827 trace("SetForegroundWindow( GetDesktopWindow() )\n");
11828 SetForegroundWindow( GetDesktopWindow() );
11829 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
11830 "foreground top level window", FALSE);
11831 trace("done\n");
11832
11833 DestroyWindow(hwnd);
11834 }
11835
11836 static void test_dbcs_wm_char(void)
11837 {
11838 BYTE dbch[2];
11839 WCHAR wch, bad_wch;
11840 HWND hwnd, hwnd2;
11841 MSG msg;
11842 DWORD time;
11843 POINT pt;
11844 DWORD_PTR res;
11845 CPINFOEXA cpinfo;
11846 UINT i, j, k;
11847 struct message wmCharSeq[2];
11848 BOOL ret;
11849
11850 if (!pGetCPInfoExA)
11851 {
11852 win_skip("GetCPInfoExA is not available\n");
11853 return;
11854 }
11855
11856 pGetCPInfoExA( CP_ACP, 0, &cpinfo );
11857 if (cpinfo.MaxCharSize != 2)
11858 {
11859 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
11860 return;
11861 }
11862
11863 dbch[0] = dbch[1] = 0;
11864 wch = 0;
11865 bad_wch = cpinfo.UnicodeDefaultChar;
11866 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
11867 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
11868 for (k = 128; k <= 255; k++)
11869 {
11870 char str[2];
11871 WCHAR wstr[2];
11872 str[0] = j;
11873 str[1] = k;
11874 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
11875 WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
11876 (BYTE)str[0] == j && (BYTE)str[1] == k &&
11877 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
11878 {
11879 dbch[0] = j;
11880 dbch[1] = k;
11881 wch = wstr[0];
11882 break;
11883 }
11884 }
11885
11886 if (!wch)
11887 {
11888 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
11889 return;
11890 }
11891 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
11892 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
11893
11894 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
11895 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11896 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
11897 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11898 ok (hwnd != 0, "Failed to create overlapped window\n");
11899 ok (hwnd2 != 0, "Failed to create overlapped window\n");
11900 flush_sequence();
11901
11902 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
11903 wmCharSeq[0].message = WM_CHAR;
11904 wmCharSeq[0].flags = sent|wparam;
11905 wmCharSeq[0].wParam = wch;
11906
11907 /* posted message */
11908 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11909 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11910 ok( !ret, "got message %x\n", msg.message );
11911 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11912 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11913 ok( ret, "no message\n" );
11914 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11915 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11916 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11917 ok( !ret, "got message %x\n", msg.message );
11918
11919 /* posted thread message */
11920 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
11921 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11922 ok( !ret, "got message %x\n", msg.message );
11923 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11924 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11925 ok( ret, "no message\n" );
11926 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11927 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11928 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11929 ok( !ret, "got message %x\n", msg.message );
11930
11931 /* sent message */
11932 flush_sequence();
11933 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11934 ok_sequence( WmEmptySeq, "no messages", FALSE );
11935 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11936 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11937 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11938 ok( !ret, "got message %x\n", msg.message );
11939
11940 /* sent message with timeout */
11941 flush_sequence();
11942 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11943 ok_sequence( WmEmptySeq, "no messages", FALSE );
11944 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11945 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11946 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11947 ok( !ret, "got message %x\n", msg.message );
11948
11949 /* sent message with timeout and callback */
11950 flush_sequence();
11951 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11952 ok_sequence( WmEmptySeq, "no messages", FALSE );
11953 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11954 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11955 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11956 ok( !ret, "got message %x\n", msg.message );
11957
11958 /* sent message with callback */
11959 flush_sequence();
11960 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11961 ok_sequence( WmEmptySeq, "no messages", FALSE );
11962 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11963 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11964 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11965 ok( !ret, "got message %x\n", msg.message );
11966
11967 /* direct window proc call */
11968 flush_sequence();
11969 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11970 ok_sequence( WmEmptySeq, "no messages", FALSE );
11971 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11972 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11973
11974 /* dispatch message */
11975 msg.hwnd = hwnd;
11976 msg.message = WM_CHAR;
11977 msg.wParam = dbch[0];
11978 msg.lParam = 0;
11979 DispatchMessageA( &msg );
11980 ok_sequence( WmEmptySeq, "no messages", FALSE );
11981 msg.wParam = dbch[1];
11982 DispatchMessageA( &msg );
11983 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11984
11985 /* window handle is irrelevant */
11986 flush_sequence();
11987 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11988 ok_sequence( WmEmptySeq, "no messages", FALSE );
11989 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11990 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11991 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11992 ok( !ret, "got message %x\n", msg.message );
11993
11994 /* interleaved post and send */
11995 flush_sequence();
11996 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11997 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11998 ok_sequence( WmEmptySeq, "no messages", FALSE );
11999 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12000 ok( !ret, "got message %x\n", msg.message );
12001 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
12002 ok_sequence( WmEmptySeq, "no messages", FALSE );
12003 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12004 ok( ret, "no message\n" );
12005 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12006 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
12007 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12008 ok( !ret, "got message %x\n", msg.message );
12009 SendMessageA( hwnd, WM_CHAR, dbch[1], 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 /* interleaved sent message and winproc */
12015 flush_sequence();
12016 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
12017 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
12018 ok_sequence( WmEmptySeq, "no messages", FALSE );
12019 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
12020 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12021 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
12022 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12023
12024 /* interleaved winproc and dispatch */
12025 msg.hwnd = hwnd;
12026 msg.message = WM_CHAR;
12027 msg.wParam = dbch[0];
12028 msg.lParam = 0;
12029 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
12030 DispatchMessageA( &msg );
12031 ok_sequence( WmEmptySeq, "no messages", FALSE );
12032 msg.wParam = dbch[1];
12033 DispatchMessageA( &msg );
12034 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12035 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
12036 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12037
12038 /* interleaved sends */
12039 flush_sequence();
12040 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
12041 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
12042 ok_sequence( WmEmptySeq, "no messages", FALSE );
12043 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
12044 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12045 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
12046 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12047
12048 /* dbcs WM_CHAR */
12049 flush_sequence();
12050 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
12051 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
12052 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12053 ok( !ret, "got message %x\n", msg.message );
12054
12055 /* other char messages are not magic */
12056 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
12057 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12058 ok( ret, "no message\n" );
12059 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
12060 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
12061 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12062 ok( !ret, "got message %x\n", msg.message );
12063 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
12064 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12065 ok( ret, "no message\n" );
12066 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
12067 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
12068 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
12069 ok( !ret, "got message %x\n", msg.message );
12070
12071 /* test retrieving messages */
12072
12073 PostMessageW( hwnd, WM_CHAR, wch, 0 );
12074 ret = PeekMessageA( &msg, hwnd, 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[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12079 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12080 ok( ret, "no message\n" );
12081 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12082 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12083 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12084 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12085 ok( !ret, "got message %x\n", msg.message );
12086
12087 /* message filters */
12088 PostMessageW( hwnd, WM_CHAR, wch, 0 );
12089 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12090 ok( ret, "no message\n" );
12091 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12092 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12093 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12094 /* message id is filtered, hwnd is not */
12095 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
12096 ok( !ret, "no message\n" );
12097 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
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, hwnd, 0, 0, PM_REMOVE );
12103 ok( !ret, "got message %x\n", msg.message );
12104
12105 /* mixing GetMessage and PostMessage */
12106 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
12107 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12108 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12109 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12110 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12111 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
12112 time = msg.time;
12113 pt = msg.pt;
12114 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
12115 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12116 ok( ret, "no message\n" );
12117 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12118 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12119 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12120 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
12121 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
12122 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 );
12123 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12124 ok( !ret, "got message %x\n", msg.message );
12125
12126 /* without PM_REMOVE */
12127 PostMessageW( hwnd, WM_CHAR, wch, 0 );
12128 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
12129 ok( ret, "no message\n" );
12130 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12131 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12132 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12133 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12134 ok( ret, "no message\n" );
12135 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12136 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12137 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12138 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
12139 ok( ret, "no message\n" );
12140 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12141 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12142 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12143 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12144 ok( ret, "no message\n" );
12145 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12146 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12147 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12148 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12149 ok( !ret, "got message %x\n", msg.message );
12150
12151 DestroyWindow(hwnd);
12152 DestroyWindow(hwnd2);
12153 }
12154
12155 static void test_unicode_wm_char(void)
12156 {
12157 HWND hwnd;
12158 MSG msg;
12159 struct message seq[2];
12160 HKL hkl_orig, hkl_greek;
12161 DWORD cp;
12162 LCID thread_locale;
12163
12164 hkl_orig = GetKeyboardLayout( 0 );
12165 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
12166 if (cp != 1252)
12167 {
12168 skip( "Default codepage %d\n", cp );
12169 return;
12170 }
12171
12172 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
12173 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
12174 {
12175 skip( "Unable to load Greek keyboard layout\n" );
12176 return;
12177 }
12178
12179 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
12180 100, 100, 200, 200, 0, 0, 0, NULL );
12181 flush_sequence();
12182
12183 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12184
12185 while (GetMessageW( &msg, hwnd, 0, 0 ))
12186 {
12187 if (!ignore_message( msg.message )) break;
12188 }
12189
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 == 0x3b1, "bad wparam %lx\n", msg.wParam );
12193 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12194
12195 DispatchMessageW( &msg );
12196
12197 memset( seq, 0, sizeof(seq) );
12198 seq[0].message = WM_CHAR;
12199 seq[0].flags = sent|wparam;
12200 seq[0].wParam = 0x3b1;
12201
12202 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12203
12204 flush_sequence();
12205
12206 /* greek alpha -> 'a' in cp1252 */
12207 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12208
12209 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12210 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12211 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12212 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
12213 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12214
12215 DispatchMessageA( &msg );
12216
12217 seq[0].wParam = 0x61;
12218 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12219
12220 thread_locale = GetThreadLocale();
12221 ActivateKeyboardLayout( hkl_greek, 0 );
12222 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
12223 thread_locale, GetThreadLocale() );
12224
12225 flush_sequence();
12226
12227 /* greek alpha -> 0xe1 in cp1253 */
12228 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12229
12230 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12231 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12232 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12233 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
12234 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12235
12236 DispatchMessageA( &msg );
12237
12238 seq[0].wParam = 0x3b1;
12239 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12240
12241 DestroyWindow( hwnd );
12242 ActivateKeyboardLayout( hkl_orig, 0 );
12243 UnloadKeyboardLayout( hkl_greek );
12244 }
12245
12246 #define ID_LISTBOX 0x000f
12247
12248 static const struct message wm_lb_setcursel_0[] =
12249 {
12250 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
12251 { WM_CTLCOLORLISTBOX, sent|parent },
12252 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
12253 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12254 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12255 { 0 }
12256 };
12257 static const struct message wm_lb_setcursel_1[] =
12258 {
12259 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
12260 { WM_CTLCOLORLISTBOX, sent|parent },
12261 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
12262 { WM_CTLCOLORLISTBOX, sent|parent },
12263 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
12264 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
12265 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
12266 { 0 }
12267 };
12268 static const struct message wm_lb_setcursel_2[] =
12269 {
12270 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
12271 { WM_CTLCOLORLISTBOX, sent|parent },
12272 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
12273 { WM_CTLCOLORLISTBOX, sent|parent },
12274 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
12275 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12276 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12277 { 0 }
12278 };
12279 static const struct message wm_lb_click_0[] =
12280 {
12281 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
12282 { HCBT_SETFOCUS, hook },
12283 { WM_KILLFOCUS, sent|parent },
12284 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
12285 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
12286 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12287 { WM_SETFOCUS, sent|defwinproc },
12288
12289 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
12290 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
12291 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12292 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
12293 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
12294
12295 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
12296 { WM_CTLCOLORLISTBOX, sent|parent },
12297 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
12298 { WM_CTLCOLORLISTBOX, sent|parent },
12299 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
12300 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
12301
12302 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12303 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12304
12305 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
12306 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
12307 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
12308 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
12309 { 0 }
12310 };
12311 static const struct message wm_lb_deletestring[] =
12312 {
12313 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
12314 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
12315 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12316 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12317 { 0 }
12318 };
12319 static const struct message wm_lb_deletestring_reset[] =
12320 {
12321 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
12322 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
12323 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
12324 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12325 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12326 { 0 }
12327 };
12328
12329 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
12330
12331 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
12332
12333 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12334 {
12335 static LONG defwndproc_counter = 0;
12336 LRESULT ret;
12337 struct recvd_message msg;
12338
12339 /* do not log painting messages */
12340 if (message != WM_PAINT &&
12341 message != WM_NCPAINT &&
12342 message != WM_SYNCPAINT &&
12343 message != WM_ERASEBKGND &&
12344 message != WM_NCHITTEST &&
12345 message != WM_GETTEXT &&
12346 !ignore_message( message ))
12347 {
12348 msg.hwnd = hwnd;
12349 msg.message = message;
12350 msg.flags = sent|wparam|lparam;
12351 if (defwndproc_counter) msg.flags |= defwinproc;
12352 msg.wParam = wp;
12353 msg.lParam = lp;
12354 msg.descr = "listbox";
12355 add_message(&msg);
12356 }
12357
12358 defwndproc_counter++;
12359 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
12360 defwndproc_counter--;
12361
12362 return ret;
12363 }
12364
12365 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
12366 int caret_index, int top_index, int line)
12367 {
12368 LRESULT ret;
12369
12370 /* calling an orig proc helps to avoid unnecessary message logging */
12371 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
12372 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
12373 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
12374 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
12375 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
12376 ok_(__FILE__, line)(ret == caret_index ||
12377 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
12378 "expected caret index %d, got %ld\n", caret_index, ret);
12379 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
12380 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
12381 }
12382
12383 static void test_listbox_messages(void)
12384 {
12385 HWND parent, listbox;
12386 LRESULT ret;
12387
12388 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12389 100, 100, 200, 200, 0, 0, 0, NULL);
12390 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
12391 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
12392 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
12393 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
12394
12395 check_lb_state(listbox, 0, LB_ERR, 0, 0);
12396
12397 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
12398 ok(ret == 0, "expected 0, got %ld\n", ret);
12399 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
12400 ok(ret == 1, "expected 1, got %ld\n", ret);
12401 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
12402 ok(ret == 2, "expected 2, got %ld\n", ret);
12403
12404 check_lb_state(listbox, 3, LB_ERR, 0, 0);
12405
12406 flush_sequence();
12407
12408 log_all_parent_messages++;
12409
12410 trace("selecting item 0\n");
12411 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
12412 ok(ret == 0, "expected 0, got %ld\n", ret);
12413 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
12414 check_lb_state(listbox, 3, 0, 0, 0);
12415 flush_sequence();
12416
12417 trace("selecting item 1\n");
12418 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
12419 ok(ret == 1, "expected 1, got %ld\n", ret);
12420 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
12421 check_lb_state(listbox, 3, 1, 1, 0);
12422
12423 trace("selecting item 2\n");
12424 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
12425 ok(ret == 2, "expected 2, got %ld\n", ret);
12426 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
12427 check_lb_state(listbox, 3, 2, 2, 0);
12428
12429 trace("clicking on item 0\n");
12430 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
12431 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12432 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
12433 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12434 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
12435 check_lb_state(listbox, 3, 0, 0, 0);
12436 flush_sequence();
12437
12438 trace("deleting item 0\n");
12439 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12440 ok(ret == 2, "expected 2, got %ld\n", ret);
12441 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12442 check_lb_state(listbox, 2, -1, 0, 0);
12443 flush_sequence();
12444
12445 trace("deleting item 0\n");
12446 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12447 ok(ret == 1, "expected 1, got %ld\n", ret);
12448 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12449 check_lb_state(listbox, 1, -1, 0, 0);
12450 flush_sequence();
12451
12452 trace("deleting item 0\n");
12453 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12454 ok(ret == 0, "expected 0, got %ld\n", ret);
12455 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
12456 check_lb_state(listbox, 0, -1, 0, 0);
12457 flush_sequence();
12458
12459 trace("deleting item 0\n");
12460 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12461 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
12462 check_lb_state(listbox, 0, -1, 0, 0);
12463 flush_sequence();
12464
12465 log_all_parent_messages--;
12466
12467 DestroyWindow(listbox);
12468 DestroyWindow(parent);
12469 }
12470
12471 /*************************** Menu test ******************************/
12472 static const struct message wm_popup_menu_1[] =
12473 {
12474 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12475 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12476 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
12477 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
12478 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
12479 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
12480 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12481 { WM_INITMENU, sent|lparam, 0, 0 },
12482 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
12483 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
12484 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
12485 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
12486 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
12487 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12488 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
12489 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
12490 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12491 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12492 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12493 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
12494 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12495 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12496 { 0 }
12497 };
12498 static const struct message wm_popup_menu_2[] =
12499 {
12500 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12501 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12502 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12503 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12504 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12505 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12506 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12507 { WM_INITMENU, sent|lparam, 0, 0 },
12508 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12509 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12510 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12511 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12512 { HCBT_CREATEWND, hook },
12513 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12514 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12515 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12516 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12517 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12518 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12519 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12520 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12521 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12522 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12523 { HCBT_DESTROYWND, hook },
12524 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12525 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12526 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12527 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12528 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12529 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
12530 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12531 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12532 { 0 }
12533 };
12534 static const struct message wm_popup_menu_3[] =
12535 {
12536 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12537 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12538 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12539 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12540 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12541 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12542 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12543 { WM_INITMENU, sent|lparam, 0, 0 },
12544 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12545 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12546 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12547 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12548 { HCBT_CREATEWND, hook },
12549 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12550 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12551 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12552 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12553 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12554 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12555 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12556 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12557 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12558 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12559 { HCBT_DESTROYWND, hook },
12560 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12561 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12562 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12563 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12564 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12565 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
12566 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12567 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12568 { 0 }
12569 };
12570
12571 static const struct message wm_single_menu_item[] =
12572 {
12573 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12574 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12575 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
12576 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
12577 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
12578 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
12579 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12580 { WM_INITMENU, sent|lparam, 0, 0 },
12581 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
12582 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12583 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12584 { WM_MENUCOMMAND, sent },
12585 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
12586 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
12587 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
12588 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
12589
12590 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
12591 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
12592 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
12593 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
12594 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
12595 { 0 }
12596 };
12597
12598 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12599 {
12600 if (message == WM_ENTERIDLE ||
12601 message == WM_INITMENU ||
12602 message == WM_INITMENUPOPUP ||
12603 message == WM_MENUSELECT ||
12604 message == WM_PARENTNOTIFY ||
12605 message == WM_ENTERMENULOOP ||
12606 message == WM_EXITMENULOOP ||
12607 message == WM_UNINITMENUPOPUP ||
12608 message == WM_KEYDOWN ||
12609 message == WM_KEYUP ||
12610 message == WM_CHAR ||
12611 message == WM_SYSKEYDOWN ||
12612 message == WM_SYSKEYUP ||
12613 message == WM_SYSCHAR ||
12614 message == WM_COMMAND ||
12615 message == WM_MENUCOMMAND)
12616 {
12617 struct recvd_message msg;
12618
12619 msg.hwnd = hwnd;
12620 msg.message = message;
12621 msg.flags = sent|wparam|lparam;
12622 msg.wParam = wp;
12623 msg.lParam = lp;
12624 msg.descr = "parent_menu_proc";
12625 add_message(&msg);
12626 }
12627
12628 return DefWindowProcA(hwnd, message, wp, lp);
12629 }
12630
12631 static void set_menu_style(HMENU hmenu, DWORD style)
12632 {
12633 MENUINFO mi;
12634 BOOL ret;
12635
12636 mi.cbSize = sizeof(mi);
12637 mi.fMask = MIM_STYLE;
12638 mi.dwStyle = style;
12639 SetLastError(0xdeadbeef);
12640 ret = pSetMenuInfo(hmenu, &mi);
12641 ok(ret, "SetMenuInfo error %u\n", GetLastError());
12642 }
12643
12644 static DWORD get_menu_style(HMENU hmenu)
12645 {
12646 MENUINFO mi;
12647 BOOL ret;
12648
12649 mi.cbSize = sizeof(mi);
12650 mi.fMask = MIM_STYLE;
12651 mi.dwStyle = 0;
12652 SetLastError(0xdeadbeef);
12653 ret = pGetMenuInfo(hmenu, &mi);
12654 ok(ret, "GetMenuInfo error %u\n", GetLastError());
12655
12656 return mi.dwStyle;
12657 }
12658
12659 static void test_menu_messages(void)
12660 {
12661 MSG msg;
12662 WNDCLASSA cls;
12663 HMENU hmenu, hmenu_popup;
12664 HWND hwnd;
12665 DWORD style;
12666
12667 if (!pGetMenuInfo || !pSetMenuInfo)
12668 {
12669 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
12670 return;
12671 }
12672 cls.style = 0;
12673 cls.lpfnWndProc = parent_menu_proc;
12674 cls.cbClsExtra = 0;
12675 cls.cbWndExtra = 0;
12676 cls.hInstance = GetModuleHandleA(0);
12677 cls.hIcon = 0;
12678 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
12679 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
12680 cls.lpszMenuName = NULL;
12681 cls.lpszClassName = "TestMenuClass";
12682 UnregisterClassA(cls.lpszClassName, cls.hInstance);
12683 if (!RegisterClassA(&cls)) assert(0);
12684
12685 SetLastError(0xdeadbeef);
12686 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12687 100, 100, 200, 200, 0, 0, 0, NULL);
12688 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
12689
12690 SetLastError(0xdeadbeef);
12691 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
12692 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
12693
12694 SetMenu(hwnd, hmenu);
12695 SetForegroundWindow( hwnd );
12696 flush_events();
12697
12698 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
12699 style = get_menu_style(hmenu);
12700 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12701
12702 hmenu_popup = GetSubMenu(hmenu, 0);
12703 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12704 style = get_menu_style(hmenu_popup);
12705 ok(style == 0, "expected 0, got %u\n", style);
12706
12707 hmenu_popup = GetSubMenu(hmenu_popup, 0);
12708 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12709 style = get_menu_style(hmenu_popup);
12710 ok(style == 0, "expected 0, got %u\n", style);
12711
12712 /* Alt+E, Enter */
12713 trace("testing a popup menu command\n");
12714 flush_sequence();
12715 keybd_event(VK_MENU, 0, 0, 0);
12716 keybd_event('E', 0, 0, 0);
12717 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
12718 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12719 keybd_event(VK_RETURN, 0, 0, 0);
12720 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12721 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12722 {
12723 TranslateMessage(&msg);
12724 DispatchMessageA(&msg);
12725 }
12726 if (!sequence_cnt) /* we didn't get any message */
12727 {
12728 skip( "queuing key events not supported\n" );
12729 goto done;
12730 }
12731 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
12732 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
12733 {
12734 win_skip( "menu tracking through VK_MENU not supported\n" );
12735 goto done;
12736 }
12737 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
12738
12739 /* Alt+F, Right, Enter */
12740 trace("testing submenu of a popup menu command\n");
12741 flush_sequence();
12742 keybd_event(VK_MENU, 0, 0, 0);
12743 keybd_event('F', 0, 0, 0);
12744 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12745 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12746 keybd_event(VK_RIGHT, 0, 0, 0);
12747 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12748 keybd_event(VK_RETURN, 0, 0, 0);
12749 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12750 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12751 {
12752 TranslateMessage(&msg);
12753 DispatchMessageA(&msg);
12754 }
12755 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
12756
12757 trace("testing single menu item command\n");
12758 flush_sequence();
12759 keybd_event(VK_MENU, 0, 0, 0);
12760 keybd_event('Q', 0, 0, 0);
12761 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
12762 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12763 keybd_event(VK_ESCAPE, 0, 0, 0);
12764 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
12765 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12766 {
12767 TranslateMessage(&msg);
12768 DispatchMessageA(&msg);
12769 }
12770 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
12771
12772 set_menu_style(hmenu, 0);
12773 style = get_menu_style(hmenu);
12774 ok(style == 0, "expected 0, got %u\n", style);
12775
12776 hmenu_popup = GetSubMenu(hmenu, 0);
12777 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12778 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
12779 style = get_menu_style(hmenu_popup);
12780 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12781
12782 hmenu_popup = GetSubMenu(hmenu_popup, 0);
12783 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12784 style = get_menu_style(hmenu_popup);
12785 ok(style == 0, "expected 0, got %u\n", style);
12786
12787 /* Alt+F, Right, Enter */
12788 trace("testing submenu of a popup menu command\n");
12789 flush_sequence();
12790 keybd_event(VK_MENU, 0, 0, 0);
12791 keybd_event('F', 0, 0, 0);
12792 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12793 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12794 keybd_event(VK_RIGHT, 0, 0, 0);
12795 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12796 keybd_event(VK_RETURN, 0, 0, 0);
12797 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12798 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12799 {
12800 TranslateMessage(&msg);
12801 DispatchMessageA(&msg);
12802 }
12803 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
12804
12805 done:
12806 DestroyWindow(hwnd);
12807 DestroyMenu(hmenu);
12808 }
12809
12810
12811 static void test_paintingloop(void)
12812 {
12813 HWND hwnd;
12814
12815 paint_loop_done = FALSE;
12816 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
12817 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
12818 100, 100, 100, 100, 0, 0, 0, NULL );
12819 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
12820 ShowWindow(hwnd,SW_NORMAL);
12821 SetFocus(hwnd);
12822
12823 while (!paint_loop_done)
12824 {
12825 MSG msg;
12826 if (PeekMessageA(&msg, 0, 0, 0, 1))
12827 {
12828 TranslateMessage(&msg);
12829 DispatchMessageA(&msg);
12830 }
12831 }
12832 DestroyWindow(hwnd);
12833 }
12834
12835 static void test_defwinproc(void)
12836 {
12837 HWND hwnd;
12838 MSG msg;
12839 BOOL gotwmquit = FALSE;
12840 hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
12841 assert(hwnd);
12842 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
12843 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
12844 if( msg.message == WM_QUIT) gotwmquit = TRUE;
12845 DispatchMessageA( &msg );
12846 }
12847 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
12848 DestroyWindow( hwnd);
12849 }
12850
12851 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
12852 static void clear_clipboard_(int line, HWND hWnd)
12853 {
12854 BOOL succ;
12855 succ = OpenClipboard(hWnd);
12856 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
12857 succ = EmptyClipboard();
12858 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
12859 succ = CloseClipboard();
12860 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
12861 }
12862
12863 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
12864 static void expect_HWND_(int line, HWND expected, HWND got)
12865 {
12866 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
12867 }
12868
12869 static WNDPROC pOldViewerProc;
12870
12871 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
12872 {
12873 static BOOL recursion_guard;
12874
12875 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
12876 {
12877 recursion_guard = TRUE;
12878 clear_clipboard(hWnd);
12879 recursion_guard = FALSE;
12880 }
12881 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
12882 }
12883
12884 static void test_clipboard_viewers(void)
12885 {
12886 static struct message wm_change_cb_chain[] =
12887 {
12888 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
12889 { 0 }
12890 };
12891 static const struct message wm_clipboard_destroyed[] =
12892 {
12893 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12894 { 0 }
12895 };
12896 static struct message wm_clipboard_changed[] =
12897 {
12898 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12899 { 0 }
12900 };
12901 static struct message wm_clipboard_changed_and_owned[] =
12902 {
12903 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12904 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12905 { 0 }
12906 };
12907
12908 HINSTANCE hInst = GetModuleHandleA(NULL);
12909 HWND hWnd1, hWnd2, hWnd3;
12910 HWND hOrigViewer;
12911 HWND hRet;
12912
12913 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
12914 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12915 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12916 GetDesktopWindow(), NULL, hInst, NULL);
12917 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
12918 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12919 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12920 GetDesktopWindow(), NULL, hInst, NULL);
12921 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
12922 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12923 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12924 GetDesktopWindow(), NULL, hInst, NULL);
12925 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
12926 assert(hWnd1 && hWnd2 && hWnd3);
12927
12928 flush_sequence();
12929
12930 /* Test getting the clipboard viewer and setting the viewer to NULL. */
12931 hOrigViewer = GetClipboardViewer();
12932 hRet = SetClipboardViewer(NULL);
12933 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
12934 expect_HWND(hOrigViewer, hRet);
12935 expect_HWND(NULL, GetClipboardViewer());
12936
12937 /* Test registering hWnd1 as a viewer. */
12938 hRet = SetClipboardViewer(hWnd1);
12939 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12940 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
12941 expect_HWND(NULL, hRet);
12942 expect_HWND(hWnd1, GetClipboardViewer());
12943
12944 /* Test that changing the clipboard actually refreshes the registered viewer. */
12945 clear_clipboard(hWnd1);
12946 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12947 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
12948
12949 /* Again, but with different owner. */
12950 clear_clipboard(hWnd2);
12951 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
12952 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
12953
12954 /* Test re-registering same window. */
12955 hRet = SetClipboardViewer(hWnd1);
12956 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12957 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
12958 expect_HWND(hWnd1, hRet);
12959 expect_HWND(hWnd1, GetClipboardViewer());
12960
12961 /* Test ChangeClipboardChain. */
12962 ChangeClipboardChain(hWnd2, hWnd3);
12963 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12964 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
12965 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
12966 expect_HWND(hWnd1, GetClipboardViewer());
12967
12968 ChangeClipboardChain(hWnd2, NULL);
12969 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12970 wm_change_cb_chain[0].lParam = 0;
12971 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
12972 expect_HWND(hWnd1, GetClipboardViewer());
12973
12974 ChangeClipboardChain(NULL, hWnd2);
12975 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
12976 expect_HWND(hWnd1, GetClipboardViewer());
12977
12978 /* Actually change clipboard viewer with ChangeClipboardChain. */
12979 ChangeClipboardChain(hWnd1, hWnd2);
12980 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
12981 expect_HWND(hWnd2, GetClipboardViewer());
12982
12983 /* Test that no refresh messages are sent when viewer has unregistered. */
12984 clear_clipboard(hWnd2);
12985 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
12986
12987 /* Register hWnd1 again. */
12988 ChangeClipboardChain(hWnd2, hWnd1);
12989 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
12990 expect_HWND(hWnd1, GetClipboardViewer());
12991
12992 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
12993 * changes the clipboard. When this happens, the system shouldn't send
12994 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
12995 */
12996 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
12997 clear_clipboard(hWnd2);
12998 /* The clipboard owner is changed in recursive_viewer_proc: */
12999 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
13000 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
13001
13002 /* Test unregistering. */
13003 ChangeClipboardChain(hWnd1, NULL);
13004 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
13005 expect_HWND(NULL, GetClipboardViewer());
13006
13007 clear_clipboard(hWnd1);
13008 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
13009
13010 DestroyWindow(hWnd1);
13011 DestroyWindow(hWnd2);
13012 DestroyWindow(hWnd3);
13013 SetClipboardViewer(hOrigViewer);
13014 }
13015
13016 static void test_PostMessage(void)
13017 {
13018 static const struct
13019 {
13020 HWND hwnd;
13021 BOOL ret;
13022 } data[] =
13023 {
13024 { HWND_TOP /* 0 */, TRUE },
13025 { HWND_BROADCAST, TRUE },
13026 { HWND_BOTTOM, TRUE },
13027 { HWND_TOPMOST, TRUE },
13028 { HWND_NOTOPMOST, FALSE },
13029 { HWND_MESSAGE, FALSE },
13030 { (HWND)0xdeadbeef, FALSE }
13031 };
13032 int i;
13033 HWND hwnd;
13034 BOOL ret;
13035 MSG msg;
13036 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
13037
13038 SetLastError(0xdeadbeef);
13039 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
13040 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
13041 {
13042 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
13043 return;
13044 }
13045 assert(hwnd);
13046
13047 flush_events();
13048
13049 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
13050 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
13051
13052 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
13053 {
13054 memset(&msg, 0xab, sizeof(msg));
13055 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
13056 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
13057 if (data[i].ret)
13058 {
13059 if (data[i].hwnd)
13060 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
13061 msg.wParam == 0x5678 && msg.lParam == 0x1234,
13062 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
13063 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
13064 else
13065 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
13066 msg.wParam == 0x1234 && msg.lParam == 0x5678,
13067 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
13068 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
13069 }
13070 }
13071
13072 DestroyWindow(hwnd);
13073 flush_events();
13074 }
13075
13076 static const struct
13077 {
13078 DWORD exp, broken;
13079 BOOL todo;
13080 } wait_idle_expect[] =
13081 {
13082 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13083 { WAIT_TIMEOUT, 0, FALSE },
13084 { WAIT_TIMEOUT, 0, FALSE },
13085 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13086 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13087 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
13088 { WAIT_TIMEOUT, 0, FALSE },
13089 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
13090 { 0, 0, FALSE },
13091 { 0, 0, FALSE },
13092 /* 10 */ { 0, 0, FALSE },
13093 { 0, 0, FALSE },
13094 { 0, WAIT_TIMEOUT, FALSE },
13095 { 0, 0, FALSE },
13096 { 0, 0, FALSE },
13097 /* 15 */ { 0, 0, FALSE },
13098 { WAIT_TIMEOUT, 0, FALSE },
13099 { WAIT_TIMEOUT, 0, FALSE },
13100 { WAIT_TIMEOUT, 0, FALSE },
13101 { WAIT_TIMEOUT, 0, FALSE },
13102 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
13103 };
13104
13105 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
13106 {
13107 MSG msg;
13108
13109 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13110 Sleep( 200 );
13111 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13112 return 0;
13113 }
13114
13115 static void do_wait_idle_child( int arg )
13116 {
13117 WNDCLASSA cls;
13118 MSG msg;
13119 HWND hwnd = 0;
13120 HANDLE thread;
13121 DWORD id;
13122 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
13123 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
13124
13125 memset( &cls, 0, sizeof(cls) );
13126 cls.lpfnWndProc = DefWindowProcA;
13127 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
13128 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
13129 cls.lpszClassName = "TestClass";
13130 RegisterClassA( &cls );
13131
13132 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
13133
13134 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
13135 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
13136
13137 switch (arg)
13138 {
13139 case 0:
13140 SetEvent( start_event );
13141 break;
13142 case 1:
13143 SetEvent( start_event );
13144 Sleep( 200 );
13145 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13146 break;
13147 case 2:
13148 SetEvent( start_event );
13149 Sleep( 200 );
13150 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13151 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
13152 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13153 break;
13154 case 3:
13155 SetEvent( start_event );
13156 Sleep( 200 );
13157 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
13158 break;
13159 case 4:
13160 SetEvent( start_event );
13161 Sleep( 200 );
13162 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13163 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
13164 break;
13165 case 5:
13166 SetEvent( start_event );
13167 Sleep( 200 );
13168 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13169 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13170 break;
13171 case 6:
13172 SetEvent( start_event );
13173 Sleep( 200 );
13174 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13175 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
13176 {
13177 GetMessageA( &msg, 0, 0, 0 );
13178 DispatchMessageA( &msg );
13179 }
13180 break;
13181 case 7:
13182 SetEvent( start_event );
13183 Sleep( 200 );
13184 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13185 SetTimer( hwnd, 3, 1, NULL );
13186 Sleep( 200 );
13187 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
13188 break;
13189 case 8:
13190 SetEvent( start_event );
13191 Sleep( 200 );
13192 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13193 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13194 break;
13195 case 9:
13196 SetEvent( start_event );
13197 Sleep( 200 );
13198 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13199 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13200 for (;;) GetMessageA( &msg, 0, 0, 0 );
13201 break;
13202 case 10:
13203 SetEvent( start_event );
13204 Sleep( 200 );
13205 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13206 SetTimer( hwnd, 3, 1, NULL );
13207 Sleep( 200 );
13208 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13209 break;
13210 case 11:
13211 SetEvent( start_event );
13212 Sleep( 200 );
13213 return; /* exiting the process makes WaitForInputIdle return success too */
13214 case 12:
13215 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13216 Sleep( 200 );
13217 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13218 SetEvent( start_event );
13219 break;
13220 case 13:
13221 SetEvent( start_event );
13222 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13223 Sleep( 200 );
13224 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
13225 WaitForSingleObject( thread, 10000 );
13226 CloseHandle( thread );
13227 break;
13228 case 14:
13229 SetEvent( start_event );
13230 Sleep( 200 );
13231 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
13232 break;
13233 case 15:
13234 SetEvent( start_event );
13235 Sleep( 200 );
13236 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
13237 break;
13238 case 16:
13239 SetEvent( start_event );
13240 Sleep( 200 );
13241 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
13242 break;
13243 case 17:
13244 SetEvent( start_event );
13245 Sleep( 200 );
13246 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
13247 break;
13248 case 18:
13249 SetEvent( start_event );
13250 Sleep( 200 );
13251 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
13252 break;
13253 case 19:
13254 SetEvent( start_event );
13255 Sleep( 200 );
13256 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
13257 break;
13258 case 20:
13259 SetEvent( start_event );
13260 Sleep( 200 );
13261 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
13262 break;
13263 }
13264 WaitForSingleObject( end_event, 2000 );
13265 CloseHandle( start_event );
13266 CloseHandle( end_event );
13267 if (hwnd) DestroyWindow( hwnd );
13268 }
13269
13270 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
13271 {
13272 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
13273 return DefWindowProcA( hwnd, msg, wp, lp );
13274 }
13275
13276 static DWORD CALLBACK wait_idle_thread( void *arg )
13277 {
13278 WNDCLASSA cls;
13279 MSG msg;
13280 HWND hwnd;
13281
13282 memset( &cls, 0, sizeof(cls) );
13283 cls.lpfnWndProc = wait_idle_proc;
13284 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
13285 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
13286 cls.lpszClassName = "TestClass";
13287 RegisterClassA( &cls );
13288
13289 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
13290 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
13291 DestroyWindow(hwnd);
13292 return 0;
13293 }
13294
13295 static void test_WaitForInputIdle( char *argv0 )
13296 {
13297 char path[MAX_PATH];
13298 PROCESS_INFORMATION pi;
13299 STARTUPINFOA startup;
13300 BOOL ret;
13301 HANDLE start_event, end_event, thread;
13302 unsigned int i;
13303 DWORD id;
13304 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
13305 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
13306 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
13307
13308 if (console_app) /* build the test with -mwindows for better coverage */
13309 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
13310
13311 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
13312 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
13313 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
13314 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
13315
13316 memset( &startup, 0, sizeof(startup) );
13317 startup.cb = sizeof(startup);
13318 startup.dwFlags = STARTF_USESHOWWINDOW;
13319 startup.wShowWindow = SW_SHOWNORMAL;
13320
13321 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
13322
13323 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
13324 {
13325 ResetEvent( start_event );
13326 ResetEvent( end_event );
13327 #if 0
13328 sprintf( path, "%s msg %u", argv0, i );
13329 #else
13330 sprintf( path, "%s msg_queue %u", argv0, i );
13331 #endif
13332 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
13333 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
13334 if (ret)
13335 {
13336 ret = WaitForSingleObject( start_event, 5000 );
13337 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
13338 if (ret == WAIT_OBJECT_0)
13339 {
13340 ret = WaitForInputIdle( pi.hProcess, 1000 );
13341 if (ret == WAIT_FAILED)
13342 ok( console_app ||
13343 ret == wait_idle_expect[i].exp ||
13344 broken(ret == wait_idle_expect[i].broken),
13345 "%u: WaitForInputIdle error %08x expected %08x\n",
13346 i, ret, wait_idle_expect[i].exp );
13347 else if (wait_idle_expect[i].todo)
13348 todo_wine
13349 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
13350 "%u: WaitForInputIdle error %08x expected %08x\n",
13351 i, ret, wait_idle_expect[i].exp );
13352 else
13353 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
13354 "%u: WaitForInputIdle error %08x expected %08x\n",
13355 i, ret, wait_idle_expect[i].exp );
13356 SetEvent( end_event );
13357 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
13358 }
13359 TerminateProcess( pi.hProcess, 0 ); /* just in case */
13360 winetest_wait_child_process( pi.hProcess );
13361 ret = WaitForInputIdle( pi.hProcess, 100 );
13362 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
13363 CloseHandle( pi.hProcess );
13364 CloseHandle( pi.hThread );
13365 }
13366 }
13367 CloseHandle( start_event );
13368 PostThreadMessageA( id, WM_QUIT, 0, 0 );
13369 WaitForSingleObject( thread, 10000 );
13370 CloseHandle( thread );
13371 }
13372
13373 static const struct message WmSetParentSeq_1[] = {
13374 { WM_SHOWWINDOW, sent|wparam, 0 },
13375 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13376 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
13377 { WM_CHILDACTIVATE, sent },
13378 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
13379 { WM_MOVE, sent|defwinproc|wparam, 0 },
13380 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13381 { WM_SHOWWINDOW, sent|wparam, 1 },
13382 { 0 }
13383 };
13384
13385 static const struct message WmSetParentSeq_2[] = {
13386 { WM_SHOWWINDOW, sent|wparam, 0 },
13387 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13388 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
13389 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13390 { HCBT_SETFOCUS, hook|optional },
13391 { WM_NCACTIVATE, sent|wparam|optional, 0 },
13392 { WM_ACTIVATE, sent|wparam|optional, 0 },
13393 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13394 { WM_KILLFOCUS, sent|wparam, 0 },
13395 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13396 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
13397 { HCBT_ACTIVATE, hook|optional },
13398 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
13399 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13400 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13401 { WM_ACTIVATE, sent|wparam|optional, 1 },
13402 { HCBT_SETFOCUS, hook|optional },
13403 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13404 { WM_SETFOCUS, sent|optional|defwinproc },
13405 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
13406 { WM_MOVE, sent|defwinproc|wparam, 0 },
13407 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13408 { WM_SHOWWINDOW, sent|wparam, 1 },
13409 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13410 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
13411 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13412 { 0 }
13413 };
13414
13415
13416 static void test_SetParent(void)
13417 {
13418 HWND parent1, parent2, child, popup;
13419 RECT rc, rc_old;
13420
13421 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13422 100, 100, 200, 200, 0, 0, 0, NULL);
13423 ok(parent1 != 0, "Failed to create parent1 window\n");
13424
13425 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13426 400, 100, 200, 200, 0, 0, 0, NULL);
13427 ok(parent2 != 0, "Failed to create parent2 window\n");
13428
13429 /* WS_CHILD window */
13430 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
13431 10, 10, 150, 150, parent1, 0, 0, NULL);
13432 ok(child != 0, "Failed to create child window\n");
13433
13434 GetWindowRect(parent1, &rc);
13435 trace("parent1 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13436 GetWindowRect(child, &rc_old);
13437 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
13438 trace("child (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13439
13440 flush_sequence();
13441
13442 SetParent(child, parent2);
13443 flush_events();
13444 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
13445
13446 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13447 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
13448
13449 GetWindowRect(parent2, &rc);
13450 trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13451 GetWindowRect(child, &rc);
13452 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
13453 trace("child (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13454
13455 ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13456 rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13457 rc.left, rc.top, rc.right, rc.bottom );
13458
13459 /* WS_POPUP window */
13460 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
13461 20, 20, 100, 100, 0, 0, 0, NULL);
13462 ok(popup != 0, "Failed to create popup window\n");
13463
13464 GetWindowRect(popup, &rc_old);
13465 trace("popup (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13466
13467 flush_sequence();
13468
13469 SetParent(popup, child);
13470 flush_events();
13471 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
13472
13473 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13474 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
13475
13476 GetWindowRect(child, &rc);
13477 trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13478 GetWindowRect(popup, &rc);
13479 MapWindowPoints(0, child, (POINT *)&rc, 2);
13480 trace("popup (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13481
13482 ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13483 rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13484 rc.left, rc.top, rc.right, rc.bottom );
13485
13486 DestroyWindow(popup);
13487 DestroyWindow(child);
13488 DestroyWindow(parent1);
13489 DestroyWindow(parent2);
13490
13491 flush_sequence();
13492 }
13493
13494 static const struct message WmKeyReleaseOnly[] = {
13495 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
13496 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
13497 { 0 }
13498 };
13499 static const struct message WmKeyPressNormal[] = {
13500 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
13501 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
13502 { 0 }
13503 };
13504 static const struct message WmKeyPressRepeat[] = {
13505 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
13506 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
13507 { 0 }
13508 };
13509 static const struct message WmKeyReleaseNormal[] = {
13510 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
13511 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
13512 { 0 }
13513 };
13514
13515 static void test_keyflags(void)
13516 {
13517 HWND test_window;
13518 SHORT key_state;
13519 BYTE keyboard_state[256];
13520 MSG msg;
13521
13522 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13523 100, 100, 200, 200, 0, 0, 0, NULL);
13524
13525 flush_events();
13526 flush_sequence();
13527
13528 /* keyup without a keydown */
13529 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13530 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13531 DispatchMessageA(&msg);
13532 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
13533
13534 key_state = GetAsyncKeyState(0x41);
13535 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13536
13537 key_state = GetKeyState(0x41);
13538 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13539
13540 /* keydown */
13541 keybd_event(0x41, 0, 0, 0);
13542 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13543 DispatchMessageA(&msg);
13544 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
13545
13546 key_state = GetAsyncKeyState(0x41);
13547 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13548
13549 key_state = GetKeyState(0x41);
13550 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13551
13552 /* keydown repeat */
13553 keybd_event(0x41, 0, 0, 0);
13554 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13555 DispatchMessageA(&msg);
13556 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
13557
13558 key_state = GetAsyncKeyState(0x41);
13559 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13560
13561 key_state = GetKeyState(0x41);
13562 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13563
13564 /* keyup */
13565 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13566 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13567 DispatchMessageA(&msg);
13568 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
13569
13570 key_state = GetAsyncKeyState(0x41);
13571 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13572
13573 key_state = GetKeyState(0x41);
13574 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13575
13576 /* set the key state in this thread */
13577 GetKeyboardState(keyboard_state);
13578 keyboard_state[0x41] = 0x80;
13579 SetKeyboardState(keyboard_state);
13580
13581 key_state = GetAsyncKeyState(0x41);
13582 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13583
13584 /* keydown */
13585 keybd_event(0x41, 0, 0, 0);
13586 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13587 DispatchMessageA(&msg);
13588 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
13589
13590 key_state = GetAsyncKeyState(0x41);
13591 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13592
13593 key_state = GetKeyState(0x41);
13594 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13595
13596 /* clear the key state in this thread */
13597 GetKeyboardState(keyboard_state);
13598 keyboard_state[0x41] = 0;
13599 SetKeyboardState(keyboard_state);
13600
13601 key_state = GetAsyncKeyState(0x41);
13602 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13603
13604 /* keyup */
13605 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13606 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13607 DispatchMessageA(&msg);
13608 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
13609
13610 key_state = GetAsyncKeyState(0x41);
13611 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13612
13613 key_state = GetKeyState(0x41);
13614 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13615
13616 DestroyWindow(test_window);
13617 flush_sequence();
13618 }
13619
13620 static const struct message WmHotkeyPressLWIN[] = {
13621 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13622 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13623 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13624 { 0 }
13625 };
13626 static const struct message WmHotkeyPress[] = {
13627 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13628 { WM_HOTKEY, sent|wparam, 5 },
13629 { 0 }
13630 };
13631 static const struct message WmHotkeyRelease[] = {
13632 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13633 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
13634 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
13635 { 0 }
13636 };
13637 static const struct message WmHotkeyReleaseLWIN[] = {
13638 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13639 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13640 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13641 { 0 }
13642 };
13643 static const struct message WmHotkeyCombined[] = {
13644 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13645 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13646 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13647 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13648 { WM_APP, sent, 0, 0 },
13649 { WM_HOTKEY, sent|wparam, 5 },
13650 { WM_APP+1, sent, 0, 0 },
13651 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13652 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13653 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13654 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13655 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13656 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13657 { 0 }
13658 };
13659 static const struct message WmHotkeyPrevious[] = {
13660 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13661 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13662 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13663 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13664 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13665 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13666 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
13667 { WM_KEYDOWN, sent|lparam, 0, 1 },
13668 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
13669 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
13670 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13671 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13672 { 0 }
13673 };
13674 static const struct message WmHotkeyNew[] = {
13675 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13676 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13677 { WM_HOTKEY, sent|wparam, 5 },
13678 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13679 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13680 { 0 }
13681 };
13682
13683 static int hotkey_letter;
13684
13685 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
13686 {
13687 struct recvd_message msg;
13688
13689 if (nCode == HC_ACTION)
13690 {
13691 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
13692
13693 msg.hwnd = 0;
13694 msg.message = wParam;
13695 msg.flags = kbd_hook|wparam|lparam;
13696 msg.wParam = kdbhookstruct->vkCode;
13697 msg.lParam = kdbhookstruct->flags;
13698 msg.descr = "KeyboardHookProc";
13699 add_message(&msg);
13700
13701 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
13702 {
13703 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
13704 "unexpected keycode %x\n", kdbhookstruct->vkCode);
13705 }
13706 }
13707
13708 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
13709 }
13710
13711 static void test_hotkey(void)
13712 {
13713 HWND test_window, taskbar_window;
13714 BOOL ret;
13715 MSG msg;
13716 DWORD queue_status;
13717 SHORT key_state;
13718
13719 SetLastError(0xdeadbeef);
13720 ret = UnregisterHotKey(NULL, 0);
13721 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13722 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13723 "unexpected error %d\n", GetLastError());
13724
13725 if (ret == TRUE)
13726 {
13727 skip("hotkeys not supported\n");
13728 return;
13729 }
13730
13731 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13732 100, 100, 200, 200, 0, 0, 0, NULL);
13733
13734 flush_sequence();
13735
13736 SetLastError(0xdeadbeef);
13737 ret = UnregisterHotKey(test_window, 0);
13738 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13739 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13740 "unexpected error %d\n", GetLastError());
13741
13742 /* Search for a Windows Key + letter combination that hasn't been registered */
13743 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
13744 {
13745 SetLastError(0xdeadbeef);
13746 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13747
13748 if (ret == TRUE)
13749 {
13750 break;
13751 }
13752 else
13753 {
13754 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13755 "unexpected error %d\n", GetLastError());
13756 }
13757 }
13758
13759 if (hotkey_letter == 0x52)
13760 {
13761 ok(0, "Couldn't find any free Windows Key + letter combination\n");
13762 goto end;
13763 }
13764
13765 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
13766 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
13767
13768 /* Same key combination, different id */
13769 SetLastError(0xdeadbeef);
13770 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
13771 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13772 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13773 "unexpected error %d\n", GetLastError());
13774
13775 /* Same key combination, different window */
13776 SetLastError(0xdeadbeef);
13777 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13778 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13779 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13780 "unexpected error %d\n", GetLastError());
13781
13782 /* Register the same hotkey twice */
13783 SetLastError(0xdeadbeef);
13784 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13785 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13786 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13787 "unexpected error %d\n", GetLastError());
13788
13789 /* Window on another thread */
13790 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
13791 if (!taskbar_window)
13792 {
13793 skip("no taskbar?\n");
13794 }
13795 else
13796 {
13797 SetLastError(0xdeadbeef);
13798 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
13799 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13800 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
13801 "unexpected error %d\n", GetLastError());
13802 }
13803
13804 /* Inject the appropriate key sequence */
13805 keybd_event(VK_LWIN, 0, 0, 0);
13806 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13807 DispatchMessageA(&msg);
13808 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
13809
13810 keybd_event(hotkey_letter, 0, 0, 0);
13811 queue_status = GetQueueStatus(QS_HOTKEY);
13812 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13813 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13814 {
13815 if (msg.message == WM_HOTKEY)
13816 {
13817 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13818 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13819 }
13820 DispatchMessageA(&msg);
13821 }
13822 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
13823
13824 queue_status = GetQueueStatus(QS_HOTKEY);
13825 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
13826
13827 key_state = GetAsyncKeyState(hotkey_letter);
13828 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13829
13830 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13831 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13832 DispatchMessageA(&msg);
13833 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
13834
13835 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13836 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13837 DispatchMessageA(&msg);
13838 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
13839
13840 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
13841 PostMessageA(test_window, WM_HOTKEY, 0, 0);
13842 queue_status = GetQueueStatus(QS_HOTKEY);
13843 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13844 queue_status = GetQueueStatus(QS_POSTMESSAGE);
13845 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
13846 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13847 DispatchMessageA(&msg);
13848 flush_sequence();
13849
13850 /* Send and process all messages at once */
13851 PostMessageA(test_window, WM_APP, 0, 0);
13852 keybd_event(VK_LWIN, 0, 0, 0);
13853 keybd_event(hotkey_letter, 0, 0, 0);
13854 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13855 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13856
13857 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13858 {
13859 if (msg.message == WM_HOTKEY)
13860 {
13861 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13862 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13863 }
13864 DispatchMessageA(&msg);
13865 }
13866 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
13867
13868 /* Register same hwnd/id with different key combination */
13869 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
13870 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13871
13872 /* Previous key combination does not work */
13873 keybd_event(VK_LWIN, 0, 0, 0);
13874 keybd_event(hotkey_letter, 0, 0, 0);
13875 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13876 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13877
13878 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13879 DispatchMessageA(&msg);
13880 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
13881
13882 /* New key combination works */
13883 keybd_event(hotkey_letter, 0, 0, 0);
13884 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13885
13886 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13887 {
13888 if (msg.message == WM_HOTKEY)
13889 {
13890 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13891 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13892 }
13893 DispatchMessageA(&msg);
13894 }
13895 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
13896
13897 /* Unregister hotkey properly */
13898 ret = UnregisterHotKey(test_window, 5);
13899 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13900
13901 /* Unregister hotkey again */
13902 SetLastError(0xdeadbeef);
13903 ret = UnregisterHotKey(test_window, 5);
13904 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13905 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13906 "unexpected error %d\n", GetLastError());
13907
13908 /* Register thread hotkey */
13909 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13910 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13911
13912 /* Inject the appropriate key sequence */
13913 keybd_event(VK_LWIN, 0, 0, 0);
13914 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13915 {
13916 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13917 DispatchMessageA(&msg);
13918 }
13919 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
13920
13921 keybd_event(hotkey_letter, 0, 0, 0);
13922 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13923 {
13924 if (msg.message == WM_HOTKEY)
13925 {
13926 struct recvd_message message;
13927 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
13928 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13929 message.message = msg.message;
13930 message.flags = sent|wparam|lparam;
13931 message.wParam = msg.wParam;
13932 message.lParam = msg.lParam;
13933 message.descr = "test_hotkey thread message";
13934 add_message(&message);
13935 }
13936 else
13937 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13938 DispatchMessageA(&msg);
13939 }
13940 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
13941
13942 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13943 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13944 {
13945 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13946 DispatchMessageA(&msg);
13947 }
13948 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
13949
13950 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13951 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13952 {
13953 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13954 DispatchMessageA(&msg);
13955 }
13956 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
13957
13958 /* Unregister thread hotkey */
13959 ret = UnregisterHotKey(NULL, 5);
13960 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13961
13962 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
13963 hKBD_hook = NULL;
13964
13965 end:
13966 UnregisterHotKey(NULL, 5);
13967 UnregisterHotKey(test_window, 5);
13968 DestroyWindow(test_window);
13969 flush_sequence();
13970 }
13971
13972
13973 static const struct message WmSetFocus_1[] = {
13974 { HCBT_SETFOCUS, hook }, /* child */
13975 { HCBT_ACTIVATE, hook }, /* parent */
13976 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
13977 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
13978 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
13979 { WM_NCACTIVATE, sent|parent },
13980 { WM_GETTEXT, sent|defwinproc|parent|optional },
13981 { WM_GETTEXT, sent|defwinproc|parent|optional },
13982 { WM_ACTIVATE, sent|wparam|parent, 1 },
13983 { HCBT_SETFOCUS, hook }, /* parent */
13984 { WM_SETFOCUS, sent|defwinproc|parent },
13985 { WM_KILLFOCUS, sent|parent },
13986 { WM_SETFOCUS, sent },
13987 { 0 }
13988 };
13989 static const struct message WmSetFocus_2[] = {
13990 { HCBT_SETFOCUS, hook }, /* parent */
13991 { WM_KILLFOCUS, sent },
13992 { WM_SETFOCUS, sent|parent },
13993 { 0 }
13994 };
13995 static const struct message WmSetFocus_3[] = {
13996 { HCBT_SETFOCUS, hook }, /* child */
13997 { 0 }
13998 };
13999 static const struct message WmSetFocus_4[] = {
14000 { 0 }
14001 };
14002
14003 static void test_SetFocus(void)
14004 {
14005 HWND parent, old_parent, child, old_focus, old_active;
14006 MSG msg;
14007 struct wnd_event wnd_event;
14008 HANDLE hthread;
14009 DWORD ret, tid;
14010
14011 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
14012 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
14013 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
14014 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
14015 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
14016 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
14017 CloseHandle(wnd_event.start_event);
14018
14019 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
14020 0, 0, 0, 0, 0, 0, 0, NULL);
14021 ok(parent != 0, "failed to create parent window\n");
14022 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
14023 0, 0, 0, 0, parent, 0, 0, NULL);
14024 ok(child != 0, "failed to create child window\n");
14025
14026 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
14027
14028 SetFocus(0);
14029 SetActiveWindow(0);
14030
14031 flush_events();
14032 flush_sequence();
14033
14034 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
14035 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
14036
14037 log_all_parent_messages++;
14038
14039 old_focus = SetFocus(child);
14040 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14041 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
14042 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
14043 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14044 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
14045
14046 old_focus = SetFocus(parent);
14047 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14048 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
14049 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
14050 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14051 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14052
14053 SetLastError(0xdeadbeef);
14054 old_focus = SetFocus((HWND)0xdeadbeef);
14055 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14056 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
14057 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14058 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
14059 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14060 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14061 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14062
14063 SetLastError(0xdeadbeef);
14064 old_focus = SetFocus(GetDesktopWindow());
14065 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
14066 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
14067 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14068 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
14069 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14070 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14071 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14072
14073 SetLastError(0xdeadbeef);
14074 old_focus = SetFocus(wnd_event.hwnd);
14075 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
14076 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
14077 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14078 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
14079 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14080 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14081 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14082
14083 SetLastError(0xdeadbeef);
14084 old_active = SetActiveWindow((HWND)0xdeadbeef);
14085 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14086 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
14087 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14088 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
14089 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
14090 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14091 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14092
14093 SetLastError(0xdeadbeef);
14094 old_active = SetActiveWindow(GetDesktopWindow());
14095 todo_wine
14096 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
14097 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14098 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
14099 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
14100 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14101 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14102
14103 SetLastError(0xdeadbeef);
14104 old_active = SetActiveWindow(wnd_event.hwnd);
14105 todo_wine
14106 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
14107 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14108 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
14109 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
14110 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14111 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14112
14113 SetLastError(0xdeadbeef);
14114 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
14115 ok(ret, "AttachThreadInput error %d\n", GetLastError());
14116
14117 todo_wine {
14118 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14119 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14120 }
14121 flush_events();
14122 flush_sequence();
14123
14124 old_focus = SetFocus(wnd_event.hwnd);
14125 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14126 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
14127 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
14128 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
14129
14130 old_focus = SetFocus(parent);
14131 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14132 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
14133 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14134 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14135
14136 flush_events();
14137 flush_sequence();
14138
14139 old_active = SetActiveWindow(wnd_event.hwnd);
14140 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14141 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
14142 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
14143 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
14144
14145 SetLastError(0xdeadbeef);
14146 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
14147 ok(ret, "AttachThreadInput error %d\n", GetLastError());
14148
14149 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
14150 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
14151
14152 old_parent = SetParent(child, GetDesktopWindow());
14153 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
14154
14155 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
14156 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
14157
14158 old_focus = SetFocus(parent);
14159 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14160 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
14161 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14162 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14163
14164 flush_events();
14165 flush_sequence();
14166
14167 SetLastError(0xdeadbeef);
14168 old_focus = SetFocus(child);
14169 todo_wine
14170 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
14171 broken(GetLastError() == 0) /* XP */ ||
14172 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
14173 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14174 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
14175 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14176 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14177 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14178
14179 SetLastError(0xdeadbeef);
14180 old_active = SetActiveWindow(child);
14181 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
14182 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14183 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
14184 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
14185 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14186 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14187
14188 log_all_parent_messages--;
14189
14190 DestroyWindow(child);
14191 DestroyWindow(parent);
14192
14193 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
14194 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
14195 ret = WaitForSingleObject(hthread, INFINITE);
14196 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
14197 CloseHandle(hthread);
14198 }
14199
14200 static const struct message WmSetLayeredStyle[] = {
14201 { WM_STYLECHANGING, sent },
14202 { WM_STYLECHANGED, sent },
14203 { WM_GETTEXT, sent|defwinproc|optional },
14204 { 0 }
14205 };
14206
14207 static const struct message WmSetLayeredStyle2[] = {
14208 { WM_STYLECHANGING, sent },
14209 { WM_STYLECHANGED, sent },
14210 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14211 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
14212 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14213 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
14214 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
14215 { 0 }
14216 };
14217
14218 struct layered_window_info
14219 {
14220 HWND hwnd;
14221 HDC hdc;
14222 SIZE size;
14223 HANDLE event;
14224 BOOL ret;
14225 };
14226
14227 static DWORD CALLBACK update_layered_proc( void *param )
14228 {
14229 struct layered_window_info *info = param;
14230 POINT src = { 0, 0 };
14231
14232 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
14233 info->hdc, &src, 0, NULL, ULW_OPAQUE );
14234 ok( info->ret, "failed\n");
14235 SetEvent( info->event );
14236 return 0;
14237 }
14238
14239 static void test_layered_window(void)
14240 {
14241 HWND hwnd;
14242 HDC hdc;
14243 HBITMAP bmp;
14244 BOOL ret;
14245 SIZE size;
14246 POINT pos, src;
14247 RECT rect, client;
14248 HANDLE thread;
14249 DWORD tid;
14250 struct layered_window_info info;
14251
14252 if (!pUpdateLayeredWindow)
14253 {
14254 win_skip( "UpdateLayeredWindow not supported\n" );
14255 return;
14256 }
14257
14258 hdc = CreateCompatibleDC( 0 );
14259 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
14260 SelectObject( hdc, bmp );
14261
14262 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
14263 100, 100, 300, 300, 0, 0, 0, NULL);
14264 ok( hwnd != 0, "failed to create window\n" );
14265 ShowWindow( hwnd, SW_SHOWNORMAL );
14266 UpdateWindow( hwnd );
14267 flush_events();
14268 flush_sequence();
14269
14270 GetWindowRect( hwnd, &rect );
14271 GetClientRect( hwnd, &client );
14272 ok( client.right < rect.right - rect.left, "wrong client area\n" );
14273 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
14274
14275 src.x = src.y = 0;
14276 pos.x = pos.y = 300;
14277 size.cx = size.cy = 250;
14278 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14279 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14280 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
14281 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
14282 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
14283
14284 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14285 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14286 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14287 GetWindowRect( hwnd, &rect );
14288 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
14289 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14290 GetClientRect( hwnd, &rect );
14291 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
14292 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14293
14294 size.cx = 150;
14295 pos.y = 200;
14296 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14297 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14298 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14299 GetWindowRect( hwnd, &rect );
14300 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
14301 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14302 GetClientRect( hwnd, &rect );
14303 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
14304 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14305
14306 SetWindowLongA( hwnd, GWL_STYLE,
14307 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
14308 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
14309
14310 size.cx = 200;
14311 pos.x = 200;
14312 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14313 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14314 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14315 GetWindowRect( hwnd, &rect );
14316 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
14317 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14318 GetClientRect( hwnd, &rect );
14319 ok( (rect.right == 200 && rect.bottom == 250) ||
14320 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
14321 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14322
14323 size.cx = 0;
14324 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14325 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14326 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(ERROR_MR_MID_NOT_FOUND) /* win7 */,
14327 "wrong error %u\n", GetLastError() );
14328 size.cx = 1;
14329 size.cy = -1;
14330 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14331 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14332 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
14333
14334 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
14335 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
14336 GetWindowRect( hwnd, &rect );
14337 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
14338 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14339 GetClientRect( hwnd, &rect );
14340 ok( (rect.right == 200 && rect.bottom == 250) ||
14341 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
14342 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14343
14344 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
14345 info.hwnd = hwnd;
14346 info.hdc = hdc;
14347 info.size.cx = 250;
14348 info.size.cy = 300;
14349 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
14350 info.ret = FALSE;
14351 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
14352 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
14353 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
14354 WaitForSingleObject( thread, 1000 );
14355 CloseHandle( thread );
14356 GetWindowRect( hwnd, &rect );
14357 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
14358 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14359 GetClientRect( hwnd, &rect );
14360 ok( (rect.right == 250 && rect.bottom == 300) ||
14361 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
14362 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14363
14364 DestroyWindow( hwnd );
14365 DeleteDC( hdc );
14366 DeleteObject( bmp );
14367 }
14368
14369 static HMENU hpopupmenu;
14370
14371 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14372 {
14373 if (ignore_message( message )) return 0;
14374
14375 switch (message) {
14376 case WM_ENTERIDLE:
14377 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
14378 EndMenu();
14379 break;
14380 case WM_INITMENU:
14381 case WM_INITMENUPOPUP:
14382 case WM_UNINITMENUPOPUP:
14383 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
14384 break;
14385 case WM_CAPTURECHANGED:
14386 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
14387 break;
14388 }
14389
14390 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
14391 }
14392
14393 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14394 {
14395 if (ignore_message( message )) return 0;
14396
14397 switch (message) {
14398 case WM_ENTERMENULOOP:
14399 ok(EndMenu() == TRUE, "EndMenu() failed\n");
14400 break;
14401 }
14402
14403 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
14404 }
14405
14406 static void test_TrackPopupMenu(void)
14407 {
14408 HWND hwnd;
14409 BOOL ret;
14410
14411 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
14412 0, 0, 1, 1, 0,
14413 NULL, NULL, 0);
14414 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
14415
14416 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
14417
14418 hpopupmenu = CreatePopupMenu();
14419 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
14420
14421 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
14422 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
14423
14424 flush_events();
14425 flush_sequence();
14426 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
14427 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
14428 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
14429
14430 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
14431
14432 flush_events();
14433 flush_sequence();
14434 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
14435 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
14436 ok(ret == TRUE, "TrackPopupMenu failed\n");
14437
14438 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
14439
14440 SetCapture(hwnd);
14441
14442 flush_events();
14443 flush_sequence();
14444 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
14445 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
14446 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
14447
14448 DestroyMenu(hpopupmenu);
14449 DestroyWindow(hwnd);
14450 }
14451
14452 static void test_TrackPopupMenuEmpty(void)
14453 {
14454 HWND hwnd;
14455 BOOL ret;
14456
14457 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
14458 0, 0, 1, 1, 0,
14459 NULL, NULL, 0);
14460 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
14461
14462 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
14463
14464 hpopupmenu = CreatePopupMenu();
14465 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
14466
14467 flush_events();
14468 flush_sequence();
14469 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
14470 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
14471 todo_wine ok(ret == 0, "TrackPopupMenu succeeded\n");
14472
14473 DestroyMenu(hpopupmenu);
14474 DestroyWindow(hwnd);
14475 }
14476
14477 static void init_funcs(void)
14478 {
14479 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
14480
14481 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
14482 X(ActivateActCtx);
14483 X(CreateActCtxW);
14484 X(DeactivateActCtx);
14485 X(GetCurrentActCtx);
14486 X(ReleaseActCtx);
14487 #undef X
14488 }
14489
14490 #if 0
14491 START_TEST(msg)
14492 {
14493 char **test_argv;
14494 BOOL ret;
14495 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
14496 HMODULE hModuleImm32;
14497 BOOL (WINAPI *pImmDisableIME)(DWORD);
14498 int argc;
14499
14500 init_funcs();
14501
14502 argc = winetest_get_mainargs( &test_argv );
14503 if (argc >= 3)
14504 {
14505 unsigned int arg;
14506 /* Child process. */
14507 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
14508 do_wait_idle_child( arg );
14509 return;
14510 }
14511
14512 InitializeCriticalSection( &sequence_cs );
14513 init_procs();
14514
14515 hModuleImm32 = LoadLibraryA("imm32.dll");
14516 if (hModuleImm32) {
14517 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
14518 if (pImmDisableIME)
14519 pImmDisableIME(0);
14520 }
14521 pImmDisableIME = NULL;
14522 FreeLibrary(hModuleImm32);
14523
14524 if (!RegisterWindowClasses()) assert(0);
14525
14526 if (pSetWinEventHook)
14527 {
14528 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
14529 GetModuleHandleA(0), win_event_proc,
14530 0, GetCurrentThreadId(),
14531 WINEVENT_INCONTEXT);
14532 if (pIsWinEventHookInstalled && hEvent_hook)
14533 {
14534 UINT event;
14535 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
14536 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
14537 }
14538 }
14539 if (!hEvent_hook) win_skip( "no win event hook support\n" );
14540
14541 cbt_hook_thread_id = GetCurrentThreadId();
14542 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
14543 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
14544
14545 test_winevents();
14546
14547 /* Fix message sequences before removing 4 lines below */
14548 if (pUnhookWinEvent && hEvent_hook)
14549 {
14550 ret = pUnhookWinEvent(hEvent_hook);
14551 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14552 pUnhookWinEvent = 0;
14553 }
14554 hEvent_hook = 0;
14555 test_SetFocus();
14556 test_SetParent();
14557 test_PostMessage();
14558 test_ShowWindow();
14559 test_PeekMessage();
14560 test_PeekMessage2();
14561 test_WaitForInputIdle( test_argv[0] );
14562 test_scrollwindowex();
14563 test_messages();
14564 test_setwindowpos();
14565 test_showwindow();
14566 invisible_parent_tests();
14567 test_mdi_messages();
14568 test_button_messages();
14569 test_static_messages();
14570 test_listbox_messages();
14571 test_combobox_messages();
14572 test_wmime_keydown_message();
14573 test_paint_messages();
14574 test_interthread_messages();
14575 test_message_conversion();
14576 test_accelerators();
14577 test_timers();
14578 test_timers_no_wnd();
14579 if (hCBT_hook) test_set_hook();
14580 test_DestroyWindow();
14581 test_DispatchMessage();
14582 test_SendMessageTimeout();
14583 test_edit_messages();
14584 test_quit_message();
14585 test_SetActiveWindow();
14586
14587 if (!pTrackMouseEvent)
14588 win_skip("TrackMouseEvent is not available\n");
14589 else
14590 test_TrackMouseEvent();
14591
14592 test_SetWindowRgn();
14593 test_sys_menu();
14594 test_dialog_messages();
14595 test_EndDialog();
14596 test_nullCallback();
14597 test_dbcs_wm_char();
14598 test_unicode_wm_char();
14599 test_menu_messages();
14600 test_paintingloop();
14601 test_defwinproc();
14602 test_clipboard_viewers();
14603 test_keyflags();
14604 test_hotkey();
14605 test_layered_window();
14606 if(!winetest_interactive)
14607 skip("CORE-8299 : Skip Tracking popup menu tests.\n");
14608 else
14609 {
14610 test_TrackPopupMenu();
14611 test_TrackPopupMenuEmpty();
14612 }
14613 /* keep it the last test, under Windows it tends to break the tests
14614 * which rely on active/foreground windows being correct.
14615 */
14616 test_SetForegroundWindow();
14617
14618 UnhookWindowsHookEx(hCBT_hook);
14619 if (pUnhookWinEvent && hEvent_hook)
14620 {
14621 ret = pUnhookWinEvent(hEvent_hook);
14622 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14623 SetLastError(0xdeadbeef);
14624 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
14625 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
14626 GetLastError() == 0xdeadbeef, /* Win9x */
14627 "unexpected error %d\n", GetLastError());
14628 }
14629 DeleteCriticalSection( &sequence_cs );
14630 }
14631 #endif
14632
14633 static void init_tests()
14634 {
14635 HMODULE hModuleImm32;
14636 BOOL (WINAPI *pImmDisableIME)(DWORD);
14637
14638 init_funcs();
14639
14640 InitializeCriticalSection( &sequence_cs );
14641 init_procs();
14642
14643 hModuleImm32 = LoadLibraryA("imm32.dll");
14644 if (hModuleImm32) {
14645 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
14646 if (pImmDisableIME)
14647 pImmDisableIME(0);
14648 }
14649 pImmDisableIME = NULL;
14650 FreeLibrary(hModuleImm32);
14651
14652 if (!RegisterWindowClasses()) assert(0);
14653
14654 cbt_hook_thread_id = GetCurrentThreadId();
14655 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
14656 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
14657 }
14658
14659 static void cleanup_tests()
14660 {
14661 BOOL ret;
14662 UnhookWindowsHookEx(hCBT_hook);
14663 if (pUnhookWinEvent && hEvent_hook)
14664 {
14665 ret = pUnhookWinEvent(hEvent_hook);
14666 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14667 SetLastError(0xdeadbeef);
14668 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
14669 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
14670 GetLastError() == 0xdeadbeef, /* Win9x */
14671 "unexpected error %d\n", GetLastError());
14672 }
14673 DeleteCriticalSection( &sequence_cs );
14674
14675 }
14676
14677 START_TEST(msg_queue)
14678 {
14679 int argc;
14680 char **test_argv;
14681 argc = winetest_get_mainargs( &test_argv );
14682 if (argc >= 3)
14683 {
14684 unsigned int arg;
14685 /* Child process. */
14686 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
14687 do_wait_idle_child( arg );
14688 return;
14689 }
14690
14691 init_tests();
14692 test_PostMessage();
14693 test_PeekMessage();
14694 test_PeekMessage2();
14695 test_interthread_messages();
14696 test_DispatchMessage();
14697 test_SendMessageTimeout();
14698 test_quit_message();
14699 test_WaitForInputIdle( test_argv[0] );
14700 test_DestroyWindow();
14701 cleanup_tests();
14702 }
14703
14704 START_TEST(msg_messages)
14705 {
14706 init_tests();
14707 test_message_conversion();
14708 test_messages();
14709 test_wmime_keydown_message();
14710 test_nullCallback();
14711 test_dbcs_wm_char();
14712 test_unicode_wm_char();
14713 test_defwinproc();
14714 cleanup_tests();
14715 }
14716
14717 START_TEST(msg_focus)
14718 {
14719 init_tests();
14720 test_SetActiveWindow();
14721 test_SetFocus();
14722
14723 /* HACK: For some reason test_SetForegroundWindow fails on Windows unless
14724 * we do this */
14725 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
14726 /* keep it the last test, under Windows it tends to break the tests
14727 * which rely on active/foreground windows being correct.
14728 */
14729 test_SetForegroundWindow();
14730 cleanup_tests();
14731 }
14732
14733 START_TEST(msg_winpos)
14734 {
14735 init_tests();
14736 test_SetParent();
14737 test_ShowWindow();
14738 test_setwindowpos();
14739 test_showwindow();
14740 test_SetWindowRgn();
14741 invisible_parent_tests();
14742 cleanup_tests();
14743 }
14744
14745 START_TEST(msg_paint)
14746 {
14747 init_tests();
14748 test_scrollwindowex();
14749 test_paint_messages();
14750 test_paintingloop();
14751 cleanup_tests();
14752 }
14753
14754 START_TEST(msg_input)
14755 {
14756 init_tests();
14757 test_accelerators();
14758 if (!pTrackMouseEvent)
14759 win_skip("TrackMouseEvent is not available\n");
14760 else
14761 test_TrackMouseEvent();
14762
14763 test_keyflags();
14764 test_hotkey();
14765 cleanup_tests();
14766 }
14767
14768 START_TEST(msg_timer)
14769 {
14770 init_tests();
14771 test_timers();
14772 test_timers_no_wnd();
14773 cleanup_tests();
14774 }
14775
14776 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
14777
14778 START_TEST(msg_hook)
14779 {
14780 // HMODULE user32 = GetModuleHandleA("user32.dll");
14781 // IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
14782 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
14783
14784 init_tests();
14785
14786 if (pSetWinEventHook)
14787 {
14788 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
14789 GetModuleHandleA(0), win_event_proc,
14790 0, GetCurrentThreadId(),
14791 WINEVENT_INCONTEXT);
14792 if (pIsWinEventHookInstalled && hEvent_hook)
14793 {
14794 UINT event;
14795 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
14796 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
14797 }
14798 }
14799 if (!hEvent_hook) win_skip( "no win event hook support\n" );
14800
14801 test_winevents();
14802
14803 /* Fix message sequences before removing 4 lines below */
14804 if (pUnhookWinEvent && hEvent_hook)
14805 {
14806 BOOL ret;
14807 ret = pUnhookWinEvent(hEvent_hook);
14808 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14809 pUnhookWinEvent = 0;
14810 }
14811 hEvent_hook = 0;
14812 if (hCBT_hook) test_set_hook();
14813 cleanup_tests();
14814 }
14815
14816 START_TEST(msg_menu)
14817 {
14818 init_tests();
14819 test_sys_menu();
14820 test_menu_messages();
14821 if(!winetest_interactive)
14822 skip("CORE-8299 : Skip Tracking popup menu tests.\n");
14823 else
14824 {
14825 test_TrackPopupMenu();
14826 test_TrackPopupMenuEmpty();
14827 }
14828 cleanup_tests();
14829 }
14830
14831 START_TEST(msg_mdi)
14832 {
14833 init_tests();
14834 test_mdi_messages();
14835 cleanup_tests();
14836 }
14837
14838 START_TEST(msg_controls)
14839 {
14840 init_tests();
14841 test_button_messages();
14842 test_static_messages();
14843 test_listbox_messages();
14844 test_combobox_messages();
14845 test_edit_messages();
14846 cleanup_tests();
14847 }
14848
14849 START_TEST(msg_layered_window)
14850 {
14851 init_tests();
14852 test_layered_window();
14853 cleanup_tests();
14854 }
14855
14856 START_TEST(msg_dialog)
14857 {
14858 init_tests();
14859 test_dialog_messages();
14860 test_EndDialog();
14861 cleanup_tests();
14862 }
14863
14864 START_TEST(msg_clipboard)
14865 {
14866 init_tests();
14867 test_clipboard_viewers();
14868 cleanup_tests();
14869 }