- ActivateActCtx seems to be broken, skip test.
[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 },
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, 1 },
453 { WM_NCACTIVATE, sent|wparam, 1 },
454 { WM_GETTEXT, sent|defwinproc|optional },
455 { WM_ACTIVATE, sent|wparam, 1 },
456 { HCBT_SETFOCUS, hook },
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, 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 },
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, 1 },
496 { WM_NCACTIVATE, sent|wparam, 1 },
497 { WM_GETTEXT, sent|defwinproc|optional },
498 { WM_ACTIVATE, sent|wparam, 1 },
499 { HCBT_SETFOCUS, hook },
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, 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_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
553 { WM_GETMINMAXINFO, sent|defwinproc },
554 { WM_NCCALCSIZE, sent|wparam, TRUE },
555 { HCBT_ACTIVATE, hook },
556 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
557 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
558 { WM_ACTIVATEAPP, sent|wparam, 1 },
559 { WM_NCACTIVATE, sent|wparam, 1 },
560 { WM_GETTEXT, sent|defwinproc|optional },
561 { WM_ACTIVATE, sent|wparam, 1 },
562 { HCBT_SETFOCUS, hook },
563 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
564 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
565 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
566 { WM_GETTEXT, sent|optional },
567 { WM_NCPAINT, sent|wparam|optional, 1 },
568 { WM_GETTEXT, sent|defwinproc|optional },
569 { WM_ERASEBKGND, sent },
570 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
571 { WM_MOVE, sent|defwinproc },
572 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
573 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
574 { WM_NCPAINT, sent|wparam|optional, 1 },
575 { WM_ERASEBKGND, sent|optional },
576 { WM_ACTIVATE, sent|wparam, 1 },
577 { WM_GETTEXT, sent|optional },
578 { WM_PAINT, sent|optional },
579 { WM_GETTITLEBARINFOEX, sent|optional },
580 { WM_NCPAINT, sent|beginpaint|optional },
581 { WM_ERASEBKGND, sent|beginpaint|optional },
582 { 0 }
583 };
584 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
585 static const struct message WmShowMinOverlappedSeq[] = {
586 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
587 { HCBT_SETFOCUS, hook },
588 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
589 { WM_KILLFOCUS, sent },
590 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
591 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
592 { WM_GETTEXT, sent|optional },
593 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
594 { WM_GETMINMAXINFO, sent|defwinproc },
595 { WM_NCCALCSIZE, sent|wparam, TRUE },
596 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
597 { WM_NCPAINT, sent|optional },
598 { WM_GETTEXT, sent|defwinproc|optional },
599 { WM_WINDOWPOSCHANGED, sent },
600 { WM_MOVE, sent|defwinproc },
601 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
602 { WM_NCCALCSIZE, sent|optional },
603 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
604 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
605 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
606 { WM_NCACTIVATE, sent|wparam, 0 },
607 { WM_GETTEXT, sent|defwinproc|optional },
608 { WM_ACTIVATE, sent },
609 { WM_ACTIVATEAPP, sent|wparam, 0 },
610
611 /* Vista sometimes restores the window right away... */
612 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
613 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
614 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
615 { WM_QUERYOPEN, sent|optional },
616 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
617 { WM_GETMINMAXINFO, sent|optional|defwinproc },
618 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
619 { HCBT_ACTIVATE, hook|optional },
620 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
621 { WM_NCACTIVATE, sent|optional },
622 { WM_GETTEXT, sent|optional },
623 { WM_ACTIVATE, sent|optional|wparam, 1 },
624 { HCBT_SETFOCUS, hook|optional },
625 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
626 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
627 { WM_SETFOCUS, sent|optional },
628 { WM_NCPAINT, sent|optional },
629 { WM_GETTEXT, sent|defwinproc|optional },
630 { WM_ERASEBKGND, sent|optional },
631 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
632 { WM_MOVE, sent|defwinproc|optional },
633 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
634 { WM_ACTIVATE, sent|optional|wparam, 1 },
635 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
636 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
637
638 { WM_PAINT, sent|optional },
639 { WM_NCPAINT, sent|beginpaint|optional },
640 { WM_ERASEBKGND, sent|beginpaint|optional },
641 { 0 }
642 };
643 /* ShowWindow(SW_HIDE) for a visible overlapped window */
644 static const struct message WmHideOverlappedSeq[] = {
645 { WM_SHOWWINDOW, sent|wparam, 0 },
646 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
647 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
648 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
649 { WM_SIZE, sent|optional }, /* XP doesn't send it */
650 { WM_MOVE, sent|optional }, /* XP doesn't send it */
651 { WM_NCACTIVATE, sent|wparam|optional, 0 },
652 { WM_ACTIVATE, sent|wparam|optional, 0 },
653 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
654 { HCBT_SETFOCUS, hook|optional },
655 { WM_KILLFOCUS, sent|wparam, 0 },
656 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
657 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
658 { 0 }
659 };
660 /* DestroyWindow for a visible overlapped window */
661 static const struct message WmDestroyOverlappedSeq[] = {
662 { HCBT_DESTROYWND, hook },
663 { 0x0090, sent|optional },
664 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
665 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
666 { 0x0090, sent|optional },
667 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
668 { WM_NCACTIVATE, sent|optional|wparam, 0 },
669 { WM_ACTIVATE, sent|optional },
670 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
671 { WM_KILLFOCUS, sent|optional|wparam, 0 },
672 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
673 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
674 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
675 { WM_DESTROY, sent },
676 { WM_NCDESTROY, sent },
677 { 0 }
678 };
679 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
680 static const struct message WmCreateMaxPopupSeq[] = {
681 { HCBT_CREATEWND, hook },
682 { WM_NCCREATE, sent },
683 { WM_NCCALCSIZE, sent|wparam, 0 },
684 { WM_CREATE, sent },
685 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
686 { WM_SIZE, sent|wparam, SIZE_RESTORED },
687 { WM_MOVE, sent },
688 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
689 { WM_GETMINMAXINFO, sent },
690 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
691 { WM_NCCALCSIZE, sent|wparam, TRUE },
692 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
693 { WM_MOVE, sent|defwinproc },
694 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
695 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
696 { WM_SHOWWINDOW, sent|wparam, 1 },
697 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
698 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
699 { HCBT_ACTIVATE, hook },
700 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
701 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
702 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
703 { WM_NCPAINT, sent|wparam|optional, 1 },
704 { WM_ERASEBKGND, sent|optional },
705 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
706 { WM_ACTIVATEAPP, sent|wparam, 1 },
707 { WM_NCACTIVATE, sent },
708 { WM_ACTIVATE, sent|wparam, 1 },
709 { HCBT_SETFOCUS, hook },
710 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
711 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
712 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
713 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
714 { WM_GETTEXT, sent|optional },
715 { WM_SYNCPAINT, sent|wparam|optional, 4 },
716 { WM_NCPAINT, sent|wparam|optional, 1 },
717 { WM_ERASEBKGND, sent|optional },
718 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
719 { WM_ERASEBKGND, sent|defwinproc|optional },
720 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
721 { 0 }
722 };
723 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
724 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
725 { HCBT_CREATEWND, hook },
726 { WM_NCCREATE, sent },
727 { WM_NCCALCSIZE, sent|wparam, 0 },
728 { WM_CREATE, sent },
729 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
730 { WM_SIZE, sent|wparam, SIZE_RESTORED },
731 { WM_MOVE, sent },
732 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
733 { WM_GETMINMAXINFO, sent },
734 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
735 { WM_NCCALCSIZE, sent|wparam, TRUE },
736 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
737 { WM_MOVE, sent|defwinproc },
738 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
739 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
740 { 0 }
741 };
742 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
743 static const struct message WmShowMaxPopupResizedSeq[] = {
744 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
745 { WM_GETMINMAXINFO, sent },
746 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
747 { WM_NCCALCSIZE, sent|wparam, TRUE },
748 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
749 { HCBT_ACTIVATE, hook },
750 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
751 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
752 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
753 { WM_NCPAINT, sent|wparam|optional, 1 },
754 { WM_ERASEBKGND, sent|optional },
755 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
756 { WM_ACTIVATEAPP, sent|wparam, 1 },
757 { WM_NCACTIVATE, sent },
758 { WM_ACTIVATE, sent|wparam, 1 },
759 { HCBT_SETFOCUS, hook },
760 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
761 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
762 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
763 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
764 { WM_GETTEXT, sent|optional },
765 { WM_NCPAINT, sent|wparam|optional, 1 },
766 { WM_ERASEBKGND, sent|optional },
767 { WM_WINDOWPOSCHANGED, sent },
768 /* WinNT4.0 sends WM_MOVE */
769 { WM_MOVE, sent|defwinproc|optional },
770 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
771 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
772 { 0 }
773 };
774 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
775 static const struct message WmShowMaxPopupSeq[] = {
776 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
777 { WM_GETMINMAXINFO, sent },
778 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
779 { WM_NCCALCSIZE, sent|wparam, TRUE },
780 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
781 { HCBT_ACTIVATE, hook },
782 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
783 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
784 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
785 { WM_ACTIVATEAPP, sent|wparam, 1 },
786 { WM_NCACTIVATE, sent },
787 { WM_ACTIVATE, sent|wparam, 1 },
788 { HCBT_SETFOCUS, hook },
789 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
790 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
791 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
792 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
793 { WM_GETTEXT, sent|optional },
794 { WM_SYNCPAINT, sent|wparam|optional, 4 },
795 { WM_NCPAINT, sent|wparam|optional, 1 },
796 { WM_ERASEBKGND, sent|optional },
797 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
798 { WM_ERASEBKGND, sent|defwinproc|optional },
799 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
800 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
801 { 0 }
802 };
803 /* CreateWindow(WS_VISIBLE) for popup window */
804 static const struct message WmCreatePopupSeq[] = {
805 { HCBT_CREATEWND, hook },
806 { WM_NCCREATE, sent },
807 { WM_NCCALCSIZE, sent|wparam, 0 },
808 { WM_CREATE, sent },
809 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
810 { WM_SIZE, sent|wparam, SIZE_RESTORED },
811 { WM_MOVE, sent },
812 { WM_SHOWWINDOW, sent|wparam, 1 },
813 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
814 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
815 { HCBT_ACTIVATE, hook },
816 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
817 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
818 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
819 { WM_NCPAINT, sent|wparam|optional, 1 },
820 { WM_ERASEBKGND, sent|optional },
821 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
822 { WM_ACTIVATEAPP, sent|wparam, 1 },
823 { WM_NCACTIVATE, sent },
824 { WM_ACTIVATE, sent|wparam, 1 },
825 { HCBT_SETFOCUS, hook },
826 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
827 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
828 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
829 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
830 { WM_GETTEXT, sent|optional },
831 { WM_SYNCPAINT, sent|wparam|optional, 4 },
832 { WM_NCPAINT, sent|wparam|optional, 1 },
833 { WM_ERASEBKGND, sent|optional },
834 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
835 { 0 }
836 };
837 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
838 static const struct message WmShowVisMaxPopupSeq[] = {
839 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
840 { WM_GETMINMAXINFO, sent },
841 { WM_GETTEXT, sent|optional },
842 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
843 { WM_GETTEXT, sent|optional },
844 { WM_NCCALCSIZE, sent|wparam, TRUE },
845 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
846 { WM_NCPAINT, sent|wparam|optional, 1 },
847 { WM_ERASEBKGND, sent|optional },
848 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
849 { WM_MOVE, sent|defwinproc },
850 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
851 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
852 { 0 }
853 };
854 /* CreateWindow (for a child popup window, not initially visible) */
855 static const struct message WmCreateChildPopupSeq[] = {
856 { HCBT_CREATEWND, hook },
857 { WM_NCCREATE, sent },
858 { WM_NCCALCSIZE, sent|wparam, 0 },
859 { WM_CREATE, sent },
860 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
861 { WM_SIZE, sent|wparam, SIZE_RESTORED },
862 { WM_MOVE, sent },
863 { 0 }
864 };
865 /* CreateWindow (for a popup window, not initially visible,
866 * which sets WS_VISIBLE in WM_CREATE handler)
867 */
868 static const struct message WmCreateInvisiblePopupSeq[] = {
869 { HCBT_CREATEWND, hook },
870 { WM_NCCREATE, sent },
871 { WM_NCCALCSIZE, sent|wparam, 0 },
872 { WM_CREATE, sent },
873 { WM_STYLECHANGING, sent },
874 { WM_STYLECHANGED, sent },
875 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
876 { WM_SIZE, sent|wparam, SIZE_RESTORED },
877 { WM_MOVE, sent },
878 { 0 }
879 };
880 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
881 * for a popup window with WS_VISIBLE style set
882 */
883 static const struct message WmShowVisiblePopupSeq_2[] = {
884 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
885 { 0 }
886 };
887 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
888 * for a popup window with WS_VISIBLE style set
889 */
890 static const struct message WmShowVisiblePopupSeq_3[] = {
891 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
892 { HCBT_ACTIVATE, hook },
893 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
894 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
895 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
896 { WM_NCACTIVATE, sent },
897 { WM_ACTIVATE, sent|wparam, 1 },
898 { HCBT_SETFOCUS, hook },
899 { WM_KILLFOCUS, sent|parent },
900 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
901 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
902 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
903 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
904 { WM_SETFOCUS, sent|defwinproc },
905 { WM_GETTEXT, sent|optional },
906 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
907 { 0 }
908 };
909 /* CreateWindow (for child window, not initially visible) */
910 static const struct message WmCreateChildSeq[] = {
911 { HCBT_CREATEWND, hook },
912 { WM_NCCREATE, sent },
913 /* child is inserted into parent's child list after WM_NCCREATE returns */
914 { WM_NCCALCSIZE, sent|wparam, 0 },
915 { WM_CREATE, sent },
916 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
917 { WM_SIZE, sent|wparam, SIZE_RESTORED },
918 { WM_MOVE, sent },
919 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
920 { 0 }
921 };
922 /* CreateWindow (for maximized child window, not initially visible) */
923 static const struct message WmCreateMaximizedChildSeq[] = {
924 { HCBT_CREATEWND, hook },
925 { WM_NCCREATE, sent },
926 { WM_NCCALCSIZE, sent|wparam, 0 },
927 { WM_CREATE, sent },
928 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
929 { WM_SIZE, sent|wparam, SIZE_RESTORED },
930 { WM_MOVE, sent },
931 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
932 { WM_GETMINMAXINFO, sent },
933 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
934 { WM_NCCALCSIZE, sent|wparam, 1 },
935 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
936 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
937 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
938 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
939 { 0 }
940 };
941 /* CreateWindow (for a child window, initially visible) */
942 static const struct message WmCreateVisibleChildSeq[] = {
943 { HCBT_CREATEWND, hook },
944 { WM_NCCREATE, sent },
945 /* child is inserted into parent's child list after WM_NCCREATE returns */
946 { WM_NCCALCSIZE, sent|wparam, 0 },
947 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
948 { WM_CREATE, sent },
949 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
950 { WM_SIZE, sent|wparam, SIZE_RESTORED },
951 { WM_MOVE, sent },
952 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
953 { WM_SHOWWINDOW, sent|wparam, 1 },
954 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
955 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
956 { WM_ERASEBKGND, sent|parent|optional },
957 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
958 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
959 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
960 { 0 }
961 };
962 /* ShowWindow(SW_SHOW) for a not visible child window */
963 static const struct message WmShowChildSeq[] = {
964 { WM_SHOWWINDOW, sent|wparam, 1 },
965 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
966 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
967 { WM_ERASEBKGND, sent|parent|optional },
968 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
969 { 0 }
970 };
971 /* ShowWindow(SW_HIDE) for a visible child window */
972 static const struct message WmHideChildSeq[] = {
973 { WM_SHOWWINDOW, sent|wparam, 0 },
974 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
975 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
976 { WM_ERASEBKGND, sent|parent|optional },
977 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
978 { 0 }
979 };
980 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
981 static const struct message WmHideChildSeq2[] = {
982 { WM_SHOWWINDOW, sent|wparam, 0 },
983 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
984 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
985 { WM_ERASEBKGND, sent|parent|optional },
986 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
987 { 0 }
988 };
989 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
990 * for a not visible child window
991 */
992 static const struct message WmShowChildSeq_2[] = {
993 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
994 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
995 { WM_CHILDACTIVATE, sent },
996 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
997 { 0 }
998 };
999 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1000 * for a not visible child window
1001 */
1002 static const struct message WmShowChildSeq_3[] = {
1003 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1004 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1005 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1006 { 0 }
1007 };
1008 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1009 * for a visible child window with a caption
1010 */
1011 static const struct message WmShowChildSeq_4[] = {
1012 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1013 { WM_CHILDACTIVATE, sent },
1014 { 0 }
1015 };
1016 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1017 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1018 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1019 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1020 { WM_NCCALCSIZE, sent|wparam, 1 },
1021 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1022 { WM_CHILDACTIVATE, sent|optional },
1023 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1024 { WM_MOVE, sent|defwinproc },
1025 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1026 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1027 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1028 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1029 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1030 { WM_GETTEXT, sent|optional },
1031 { 0 }
1032 };
1033 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1034 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1035 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1036 { 0 }
1037 };
1038 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1039 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1040 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1041 { WM_GETMINMAXINFO, sent },
1042 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1043 { WM_NCCALCSIZE, sent|wparam, 1 },
1044 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1045 { WM_CHILDACTIVATE, sent },
1046 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1047 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1048 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1049 { 0 }
1050 };
1051 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1052 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1053 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1054 { 0 }
1055 };
1056 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1057 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1058 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1059 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1060 { WM_NCCALCSIZE, sent|wparam, 1 },
1061 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1062 { WM_CHILDACTIVATE, sent },
1063 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1064 { WM_MOVE, sent|defwinproc },
1065 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1066 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1067 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1068 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1069 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1070 { WM_GETTEXT, sent|optional },
1071 { 0 }
1072 };
1073 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1074 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1075 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1076 { 0 }
1077 };
1078 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1079 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1080 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1081 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1082 { WM_NCCALCSIZE, sent|wparam, 1 },
1083 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1084 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1085 { WM_MOVE, sent|defwinproc },
1086 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1087 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1088 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1089 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1090 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1091 { WM_GETTEXT, sent|optional },
1092 { 0 }
1093 };
1094 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1095 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1096 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1097 { 0 }
1098 };
1099 /* ShowWindow(SW_SHOW) for child with invisible parent */
1100 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1101 { WM_SHOWWINDOW, sent|wparam, 1 },
1102 { 0 }
1103 };
1104 /* ShowWindow(SW_HIDE) for child with invisible parent */
1105 static const struct message WmHideChildInvisibleParentSeq[] = {
1106 { WM_SHOWWINDOW, sent|wparam, 0 },
1107 { 0 }
1108 };
1109 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1110 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1111 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1112 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1113 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1114 { 0 }
1115 };
1116 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1117 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1118 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1119 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1120 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1121 { 0 }
1122 };
1123 /* DestroyWindow for a visible child window */
1124 static const struct message WmDestroyChildSeq[] = {
1125 { HCBT_DESTROYWND, hook },
1126 { 0x0090, sent|optional },
1127 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1128 { WM_SHOWWINDOW, sent|wparam, 0 },
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_ERASEBKGND, sent|parent|optional },
1132 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1133 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1134 { WM_KILLFOCUS, sent },
1135 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1136 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1137 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1138 { WM_SETFOCUS, sent|parent },
1139 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1140 { WM_DESTROY, sent },
1141 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1142 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1143 { WM_NCDESTROY, sent },
1144 { 0 }
1145 };
1146 /* visible child window destroyed by thread exit */
1147 static const struct message WmExitThreadSeq[] = {
1148 { WM_NCDESTROY, sent }, /* actually in grandchild */
1149 { WM_PAINT, sent|parent },
1150 { WM_ERASEBKGND, sent|parent|beginpaint },
1151 { 0 }
1152 };
1153 /* DestroyWindow for a visible child window with invisible parent */
1154 static const struct message WmDestroyInvisibleChildSeq[] = {
1155 { HCBT_DESTROYWND, hook },
1156 { 0x0090, sent|optional },
1157 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1158 { WM_SHOWWINDOW, sent|wparam, 0 },
1159 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1160 { WM_DESTROY, sent },
1161 { WM_NCDESTROY, sent },
1162 { 0 }
1163 };
1164 /* Moving the mouse in nonclient area */
1165 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1166 { WM_NCHITTEST, sent },
1167 { WM_SETCURSOR, sent },
1168 { WM_NCMOUSEMOVE, posted },
1169 { 0 }
1170 };
1171 /* Moving the mouse in client area */
1172 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1173 { WM_NCHITTEST, sent },
1174 { WM_SETCURSOR, sent },
1175 { WM_MOUSEMOVE, posted },
1176 { 0 }
1177 };
1178 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1179 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1180 { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1181 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1182 { WM_GETMINMAXINFO, sent|defwinproc },
1183 { WM_ENTERSIZEMOVE, sent|defwinproc },
1184 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1185 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1186 { WM_MOVE, sent|defwinproc },
1187 { WM_EXITSIZEMOVE, sent|defwinproc },
1188 { 0 }
1189 };
1190 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1191 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1192 { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1193 { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1194 { WM_GETMINMAXINFO, sent|defwinproc },
1195 { WM_ENTERSIZEMOVE, sent|defwinproc },
1196 { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1197 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1198 { WM_GETMINMAXINFO, sent|defwinproc },
1199 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1200 { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1201 { WM_GETTEXT, sent|defwinproc },
1202 { WM_ERASEBKGND, sent|defwinproc },
1203 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1204 { WM_MOVE, sent|defwinproc },
1205 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1206 { WM_EXITSIZEMOVE, sent|defwinproc },
1207 { 0 }
1208 };
1209 /* Resizing child window with MoveWindow (32) */
1210 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1211 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1212 { WM_NCCALCSIZE, sent|wparam, 1 },
1213 { WM_ERASEBKGND, sent|parent|optional },
1214 { WM_ERASEBKGND, sent|optional },
1215 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1216 { WM_MOVE, sent|defwinproc },
1217 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1218 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1219 { 0 }
1220 };
1221 /* Clicking on inactive button */
1222 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1223 { WM_NCHITTEST, sent },
1224 { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1225 { WM_MOUSEACTIVATE, sent },
1226 { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1227 { WM_SETCURSOR, sent },
1228 { WM_SETCURSOR, sent|parent|defwinproc },
1229 { WM_LBUTTONDOWN, posted },
1230 { WM_KILLFOCUS, posted|parent },
1231 { WM_SETFOCUS, posted },
1232 { WM_CTLCOLORBTN, posted|parent },
1233 { BM_SETSTATE, posted },
1234 { WM_CTLCOLORBTN, posted|parent },
1235 { WM_LBUTTONUP, posted },
1236 { BM_SETSTATE, posted },
1237 { WM_CTLCOLORBTN, posted|parent },
1238 { WM_COMMAND, posted|parent },
1239 { 0 }
1240 };
1241 /* Reparenting a button (16/32) */
1242 /* The last child (button) reparented gets topmost for its new parent. */
1243 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1244 { WM_SHOWWINDOW, sent|wparam, 0 },
1245 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1246 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1247 { WM_ERASEBKGND, sent|parent },
1248 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1249 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1250 { WM_CHILDACTIVATE, sent },
1251 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1252 { WM_MOVE, sent|defwinproc },
1253 { WM_SHOWWINDOW, sent|wparam, 1 },
1254 { 0 }
1255 };
1256 /* Creation of a custom dialog (32) */
1257 static const struct message WmCreateCustomDialogSeq[] = {
1258 { HCBT_CREATEWND, hook },
1259 { WM_GETMINMAXINFO, sent },
1260 { WM_NCCREATE, sent },
1261 { WM_NCCALCSIZE, sent|wparam, 0 },
1262 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1263 { WM_CREATE, sent },
1264 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1265 { WM_NOTIFYFORMAT, sent|optional },
1266 { WM_QUERYUISTATE, sent|optional },
1267 { WM_WINDOWPOSCHANGING, sent|optional },
1268 { WM_GETMINMAXINFO, sent|optional },
1269 { WM_NCCALCSIZE, sent|optional },
1270 { WM_WINDOWPOSCHANGED, sent|optional },
1271 { WM_SHOWWINDOW, sent|wparam, 1 },
1272 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1273 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1274 { HCBT_ACTIVATE, hook },
1275 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1276
1277
1278 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1279
1280 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1281
1282 { WM_NCACTIVATE, sent },
1283 { WM_GETTEXT, sent|optional|defwinproc },
1284 { WM_GETTEXT, sent|optional|defwinproc },
1285 { WM_GETTEXT, sent|optional|defwinproc },
1286 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1287 { WM_ACTIVATE, sent|wparam, 1 },
1288 { WM_GETTEXT, sent|optional },
1289 { WM_KILLFOCUS, sent|parent },
1290 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1291 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1292 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1293 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1294 { WM_SETFOCUS, sent },
1295 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1296 { WM_NCPAINT, sent|wparam, 1 },
1297 { WM_GETTEXT, sent|optional|defwinproc },
1298 { WM_GETTEXT, sent|optional|defwinproc },
1299 { WM_ERASEBKGND, sent },
1300 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1301 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1302 { WM_GETTEXT, sent|optional },
1303 { WM_GETTEXT, sent|optional },
1304 { WM_NCCALCSIZE, sent|optional },
1305 { WM_NCPAINT, sent|optional },
1306 { WM_GETTEXT, sent|optional|defwinproc },
1307 { WM_GETTEXT, sent|optional|defwinproc },
1308 { WM_ERASEBKGND, sent|optional },
1309 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1310 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1311 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1312 { WM_MOVE, sent },
1313 { 0 }
1314 };
1315 /* Calling EndDialog for a custom dialog (32) */
1316 static const struct message WmEndCustomDialogSeq[] = {
1317 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1318 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1319 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1320 { WM_GETTEXT, sent|optional },
1321 { HCBT_ACTIVATE, hook },
1322 { WM_NCACTIVATE, sent|wparam, 0 },
1323 { WM_GETTEXT, sent|optional|defwinproc },
1324 { WM_GETTEXT, sent|optional|defwinproc },
1325 { WM_ACTIVATE, sent|wparam, 0 },
1326 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1327 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1328 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1329 { WM_GETTEXT, sent|optional|defwinproc },
1330 { WM_GETTEXT, sent|optional|defwinproc },
1331 { HCBT_SETFOCUS, hook },
1332 { WM_KILLFOCUS, sent },
1333 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1334 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1335 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1336 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1337 { WM_SETFOCUS, sent|parent|defwinproc },
1338 { 0 }
1339 };
1340 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1341 static const struct message WmShowCustomDialogSeq[] = {
1342 { WM_SHOWWINDOW, sent|wparam, 1 },
1343 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1344 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1345 { HCBT_ACTIVATE, hook },
1346 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1347
1348 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1349
1350 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1351 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1352 { WM_NCACTIVATE, sent },
1353 { WM_ACTIVATE, sent|wparam, 1 },
1354 { WM_GETTEXT, sent|optional },
1355
1356 { WM_KILLFOCUS, sent|parent },
1357 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1358 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1359 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1360 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1361 { WM_SETFOCUS, sent },
1362 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1363 { WM_NCPAINT, sent|wparam, 1 },
1364 { WM_ERASEBKGND, sent },
1365 { WM_CTLCOLORDLG, sent|defwinproc },
1366 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1367 { 0 }
1368 };
1369 /* Creation and destruction of a modal dialog (32) */
1370 static const struct message WmModalDialogSeq[] = {
1371 { WM_CANCELMODE, sent|parent },
1372 { HCBT_SETFOCUS, hook },
1373 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1374 { WM_KILLFOCUS, sent|parent },
1375 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1376 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1377 { WM_ENABLE, sent|parent|wparam, 0 },
1378 { HCBT_CREATEWND, hook },
1379 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1380 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1381 { WM_SETFONT, sent },
1382 { WM_INITDIALOG, sent },
1383 { WM_CHANGEUISTATE, sent|optional },
1384 { WM_UPDATEUISTATE, sent|optional },
1385 { WM_SHOWWINDOW, sent },
1386 { HCBT_ACTIVATE, hook },
1387 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1388 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1389 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1390 { WM_NCACTIVATE, sent },
1391 { WM_GETTEXT, sent|optional },
1392 { WM_ACTIVATE, sent|wparam, 1 },
1393 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1394 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1395 { WM_NCPAINT, sent|optional },
1396 { WM_GETTEXT, sent|optional },
1397 { WM_ERASEBKGND, sent|optional },
1398 { WM_CTLCOLORDLG, sent|optional },
1399 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1400 { WM_GETTEXT, sent|optional },
1401 { WM_NCCALCSIZE, sent|optional },
1402 { WM_NCPAINT, sent|optional },
1403 { WM_GETTEXT, sent|optional },
1404 { WM_ERASEBKGND, sent|optional },
1405 { WM_CTLCOLORDLG, sent|optional },
1406 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1407 { WM_PAINT, sent|optional },
1408 { WM_CTLCOLORBTN, sent|optional },
1409 { WM_GETTITLEBARINFOEX, sent|optional },
1410 { WM_ENTERIDLE, sent|parent|optional },
1411 { WM_ENTERIDLE, sent|parent|optional },
1412 { WM_ENTERIDLE, sent|parent|optional },
1413 { WM_ENTERIDLE, sent|parent|optional },
1414 { WM_ENTERIDLE, sent|parent|optional },
1415 { WM_ENTERIDLE, sent|parent|optional },
1416 { WM_ENTERIDLE, sent|parent|optional },
1417 { WM_ENTERIDLE, sent|parent|optional },
1418 { WM_ENTERIDLE, sent|parent|optional },
1419 { WM_ENTERIDLE, sent|parent|optional },
1420 { WM_ENTERIDLE, sent|parent|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_TIMER, sent },
1431 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1432 { WM_ENABLE, sent|parent|wparam, 1 },
1433 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1434 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1435 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1436 { WM_GETTEXT, sent|optional },
1437 { HCBT_ACTIVATE, hook },
1438 { WM_NCACTIVATE, sent|wparam, 0 },
1439 { WM_GETTEXT, sent|optional },
1440 { WM_ACTIVATE, sent|wparam, 0 },
1441 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1442 { WM_WINDOWPOSCHANGING, sent|optional },
1443 { WM_WINDOWPOSCHANGED, sent|optional },
1444 { HCBT_SETFOCUS, hook },
1445 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1446 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1447 { WM_SETFOCUS, sent|parent|defwinproc },
1448 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1449 { HCBT_DESTROYWND, hook },
1450 { 0x0090, sent|optional },
1451 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1452 { WM_DESTROY, sent },
1453 { WM_NCDESTROY, sent },
1454 { 0 }
1455 };
1456 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1457 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1458 /* (inside dialog proc, handling WM_INITDIALOG) */
1459 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1460 { WM_NCCALCSIZE, sent },
1461 { WM_NCACTIVATE, sent|parent|wparam, 0 },
1462 { WM_GETTEXT, sent|defwinproc },
1463 { WM_ACTIVATE, sent|parent|wparam, 0 },
1464 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1465 { WM_WINDOWPOSCHANGING, sent|parent },
1466 { WM_NCACTIVATE, sent|wparam, 1 },
1467 { WM_ACTIVATE, sent|wparam, 1 },
1468 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1469 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1470 /* (setting focus) */
1471 { WM_SHOWWINDOW, sent|wparam, 1 },
1472 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1473 { WM_NCPAINT, sent },
1474 { WM_GETTEXT, sent|defwinproc },
1475 { WM_ERASEBKGND, sent },
1476 { WM_CTLCOLORDLG, sent|defwinproc },
1477 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1478 { WM_PAINT, sent },
1479 /* (bunch of WM_CTLCOLOR* for each control) */
1480 { WM_PAINT, sent|parent },
1481 { WM_ENTERIDLE, sent|parent|wparam, 0 },
1482 { WM_SETCURSOR, sent|parent },
1483 { 0 }
1484 };
1485 /* SetMenu for NonVisible windows with size change*/
1486 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1487 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1488 { WM_NCCALCSIZE, sent|wparam, 1 },
1489 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1490 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1491 { WM_MOVE, sent|defwinproc },
1492 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1493 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1494 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1495 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1496 { WM_GETTEXT, sent|optional },
1497 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1498 { 0 }
1499 };
1500 /* SetMenu for NonVisible windows with no size change */
1501 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1502 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1503 { WM_NCCALCSIZE, sent|wparam, 1 },
1504 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1505 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1506 { 0 }
1507 };
1508 /* SetMenu for Visible windows with size change */
1509 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1510 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1511 { WM_NCCALCSIZE, sent|wparam, 1 },
1512 { 0x0093, sent|defwinproc|optional },
1513 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1514 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1515 { 0x0093, sent|defwinproc|optional },
1516 { 0x0093, sent|defwinproc|optional },
1517 { 0x0091, sent|defwinproc|optional },
1518 { 0x0092, sent|defwinproc|optional },
1519 { WM_GETTEXT, sent|defwinproc|optional },
1520 { WM_ERASEBKGND, sent|optional },
1521 { WM_ACTIVATE, sent|optional },
1522 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1523 { WM_MOVE, sent|defwinproc },
1524 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1525 { 0x0093, sent|optional },
1526 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1527 { 0x0093, sent|defwinproc|optional },
1528 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1529 { 0x0093, sent|defwinproc|optional },
1530 { 0x0093, sent|defwinproc|optional },
1531 { 0x0091, sent|defwinproc|optional },
1532 { 0x0092, sent|defwinproc|optional },
1533 { WM_ERASEBKGND, sent|optional },
1534 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1535 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1536 { 0 }
1537 };
1538 /* SetMenu for Visible windows with no size change */
1539 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1540 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1541 { WM_NCCALCSIZE, sent|wparam, 1 },
1542 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1543 { WM_GETTEXT, sent|defwinproc|optional },
1544 { WM_ERASEBKGND, sent|optional },
1545 { WM_ACTIVATE, sent|optional },
1546 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1547 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1548 { 0 }
1549 };
1550 /* DrawMenuBar for a visible window */
1551 static const struct message WmDrawMenuBarSeq[] =
1552 {
1553 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1554 { WM_NCCALCSIZE, sent|wparam, 1 },
1555 { 0x0093, sent|defwinproc|optional },
1556 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1557 { 0x0093, sent|defwinproc|optional },
1558 { 0x0093, sent|defwinproc|optional },
1559 { 0x0091, sent|defwinproc|optional },
1560 { 0x0092, sent|defwinproc|optional },
1561 { WM_GETTEXT, sent|defwinproc|optional },
1562 { WM_ERASEBKGND, sent|optional },
1563 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1564 { 0x0093, sent|optional },
1565 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1566 { 0 }
1567 };
1568
1569 static const struct message WmSetRedrawFalseSeq[] =
1570 {
1571 { WM_SETREDRAW, sent|wparam, 0 },
1572 { 0 }
1573 };
1574
1575 static const struct message WmSetRedrawTrueSeq[] =
1576 {
1577 { WM_SETREDRAW, sent|wparam, 1 },
1578 { 0 }
1579 };
1580
1581 static const struct message WmEnableWindowSeq_1[] =
1582 {
1583 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1584 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1585 { HCBT_SETFOCUS, hook|optional },
1586 { WM_KILLFOCUS, sent|optional },
1587 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1588 { 0 }
1589 };
1590
1591 static const struct message WmEnableWindowSeq_2[] =
1592 {
1593 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1594 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1595 { 0 }
1596 };
1597
1598 static const struct message WmGetScrollRangeSeq[] =
1599 {
1600 { SBM_GETRANGE, sent },
1601 { 0 }
1602 };
1603 static const struct message WmGetScrollInfoSeq[] =
1604 {
1605 { SBM_GETSCROLLINFO, sent },
1606 { 0 }
1607 };
1608 static const struct message WmSetScrollRangeSeq[] =
1609 {
1610 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1611 sends SBM_SETSCROLLINFO.
1612 */
1613 { SBM_SETSCROLLINFO, sent },
1614 { 0 }
1615 };
1616 /* SetScrollRange for a window without a non-client area */
1617 static const struct message WmSetScrollRangeHSeq_empty[] =
1618 {
1619 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1620 { 0 }
1621 };
1622 static const struct message WmSetScrollRangeVSeq_empty[] =
1623 {
1624 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1625 { 0 }
1626 };
1627 static const struct message WmSetScrollRangeHVSeq[] =
1628 {
1629 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1630 { WM_NCCALCSIZE, sent|wparam, 1 },
1631 { WM_GETTEXT, sent|defwinproc|optional },
1632 { WM_ERASEBKGND, sent|optional },
1633 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1634 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1635 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1636 { 0 }
1637 };
1638 /* SetScrollRange for a window with a non-client area */
1639 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1640 {
1641 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1642 { WM_NCCALCSIZE, sent|wparam, 1 },
1643 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1644 { WM_NCPAINT, sent|optional },
1645 { WM_STYLECHANGING, sent|defwinproc|optional },
1646 { WM_STYLECHANGED, sent|defwinproc|optional },
1647 { WM_STYLECHANGING, sent|defwinproc|optional },
1648 { WM_STYLECHANGED, sent|defwinproc|optional },
1649 { WM_STYLECHANGING, sent|defwinproc|optional },
1650 { WM_STYLECHANGED, sent|defwinproc|optional },
1651 { WM_STYLECHANGING, sent|defwinproc|optional },
1652 { WM_STYLECHANGED, sent|defwinproc|optional },
1653 { WM_GETTEXT, sent|defwinproc|optional },
1654 { WM_GETTEXT, sent|defwinproc|optional },
1655 { WM_ERASEBKGND, sent|optional },
1656 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1657 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1658 { WM_SIZE, sent|defwinproc|optional },
1659 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1660 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1661 { WM_GETTEXT, sent|optional },
1662 { WM_GETTEXT, sent|optional },
1663 { WM_GETTEXT, sent|optional },
1664 { WM_GETTEXT, sent|optional },
1665 { 0 }
1666 };
1667 /* test if we receive the right sequence of messages */
1668 /* after calling ShowWindow( SW_SHOWNA) */
1669 static const struct message WmSHOWNAChildInvisParInvis[] = {
1670 { WM_SHOWWINDOW, sent|wparam, 1 },
1671 { 0 }
1672 };
1673 static const struct message WmSHOWNAChildVisParInvis[] = {
1674 { WM_SHOWWINDOW, sent|wparam, 1 },
1675 { 0 }
1676 };
1677 static const struct message WmSHOWNAChildVisParVis[] = {
1678 { WM_SHOWWINDOW, sent|wparam, 1 },
1679 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1680 { 0 }
1681 };
1682 static const struct message WmSHOWNAChildInvisParVis[] = {
1683 { WM_SHOWWINDOW, sent|wparam, 1 },
1684 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1685 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1686 { WM_ERASEBKGND, sent|optional },
1687 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1688 { 0 }
1689 };
1690 static const struct message WmSHOWNATopVisible[] = {
1691 { WM_SHOWWINDOW, sent|wparam, 1 },
1692 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1693 { WM_NCPAINT, sent|wparam|optional, 1 },
1694 { WM_GETTEXT, sent|defwinproc|optional },
1695 { WM_ERASEBKGND, sent|optional },
1696 { WM_WINDOWPOSCHANGED, sent|optional },
1697 { 0 }
1698 };
1699 static const struct message WmSHOWNATopInvisible[] = {
1700 { WM_NOTIFYFORMAT, sent|optional },
1701 { WM_QUERYUISTATE, sent|optional },
1702 { WM_WINDOWPOSCHANGING, sent|optional },
1703 { WM_GETMINMAXINFO, sent|optional },
1704 { WM_NCCALCSIZE, sent|optional },
1705 { WM_WINDOWPOSCHANGED, sent|optional },
1706 { WM_SHOWWINDOW, sent|wparam, 1 },
1707 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1708 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1709 { WM_NCPAINT, sent|wparam|optional, 1 },
1710 { WM_GETTEXT, sent|defwinproc|optional },
1711 { WM_ERASEBKGND, sent|optional },
1712 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1713 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1714 { WM_NCPAINT, sent|wparam|optional, 1 },
1715 { WM_ERASEBKGND, sent|optional },
1716 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1717 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1718 { WM_MOVE, sent },
1719 { 0 }
1720 };
1721
1722 static int after_end_dialog, test_def_id;
1723 static int sequence_cnt, sequence_size;
1724 static struct recvd_message* sequence;
1725 static int log_all_parent_messages;
1726 static int paint_loop_done;
1727
1728 /* user32 functions */
1729 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1730 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1731 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1732 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1733 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1734 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1735 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1736 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
1737 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
1738 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
1739 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
1740 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
1741 /* kernel32 functions */
1742 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1743
1744 static void init_procs(void)
1745 {
1746 HMODULE user32 = GetModuleHandleA("user32.dll");
1747 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1748
1749 #define GET_PROC(dll, func) \
1750 p ## func = (void*)GetProcAddress(dll, #func); \
1751 if(!p ## func) { \
1752 trace("GetProcAddress(%s) failed\n", #func); \
1753 }
1754
1755 GET_PROC(user32, GetAncestor)
1756 GET_PROC(user32, GetMenuInfo)
1757 GET_PROC(user32, NotifyWinEvent)
1758 GET_PROC(user32, SetMenuInfo)
1759 GET_PROC(user32, SetWinEventHook)
1760 GET_PROC(user32, TrackMouseEvent)
1761 GET_PROC(user32, UnhookWinEvent)
1762 GET_PROC(user32, GetMonitorInfoA)
1763 GET_PROC(user32, MonitorFromPoint)
1764 GET_PROC(user32, UpdateLayeredWindow)
1765 GET_PROC(user32, SetSystemTimer)
1766 GET_PROC(user32, KillSystemTimer)
1767
1768 GET_PROC(kernel32, GetCPInfoExA)
1769
1770 #undef GET_PROC
1771 }
1772
1773 static const char *get_winpos_flags(UINT flags)
1774 {
1775 static char buffer[300];
1776
1777 buffer[0] = 0;
1778 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1779 DUMP( SWP_SHOWWINDOW );
1780 DUMP( SWP_HIDEWINDOW );
1781 DUMP( SWP_NOACTIVATE );
1782 DUMP( SWP_FRAMECHANGED );
1783 DUMP( SWP_NOCOPYBITS );
1784 DUMP( SWP_NOOWNERZORDER );
1785 DUMP( SWP_NOSENDCHANGING );
1786 DUMP( SWP_DEFERERASE );
1787 DUMP( SWP_ASYNCWINDOWPOS );
1788 DUMP( SWP_NOZORDER );
1789 DUMP( SWP_NOREDRAW );
1790 DUMP( SWP_NOSIZE );
1791 DUMP( SWP_NOMOVE );
1792 DUMP( SWP_NOCLIENTSIZE );
1793 DUMP( SWP_NOCLIENTMOVE );
1794 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1795 return buffer + 1;
1796 #undef DUMP
1797 }
1798
1799 static BOOL ignore_message( UINT message )
1800 {
1801 /* these are always ignored */
1802 return (message >= 0xc000 ||
1803 message == WM_GETICON ||
1804 message == WM_GETOBJECT ||
1805 message == WM_TIMECHANGE ||
1806 message == WM_DISPLAYCHANGE ||
1807 message == WM_DEVICECHANGE ||
1808 message == WM_DWMNCRENDERINGCHANGED);
1809 }
1810
1811
1812 #define add_message(msg) add_message_(__LINE__,msg);
1813 static void add_message_(int line, const struct recvd_message *msg)
1814 {
1815 struct recvd_message *seq;
1816
1817 if (!sequence)
1818 {
1819 sequence_size = 10;
1820 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1821 }
1822 if (sequence_cnt == sequence_size)
1823 {
1824 sequence_size *= 2;
1825 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1826 }
1827 assert(sequence);
1828
1829 seq = &sequence[sequence_cnt];
1830 seq->hwnd = msg->hwnd;
1831 seq->message = msg->message;
1832 seq->flags = msg->flags;
1833 seq->wParam = msg->wParam;
1834 seq->lParam = msg->lParam;
1835 seq->line = line;
1836 seq->descr = msg->descr;
1837 seq->output[0] = 0;
1838
1839 if (msg->descr)
1840 {
1841 if (msg->flags & hook)
1842 {
1843 static const char * const CBT_code_name[10] =
1844 {
1845 "HCBT_MOVESIZE",
1846 "HCBT_MINMAX",
1847 "HCBT_QS",
1848 "HCBT_CREATEWND",
1849 "HCBT_DESTROYWND",
1850 "HCBT_ACTIVATE",
1851 "HCBT_CLICKSKIPPED",
1852 "HCBT_KEYSKIPPED",
1853 "HCBT_SYSCOMMAND",
1854 "HCBT_SETFOCUS"
1855 };
1856 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1857
1858 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1859 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1860 }
1861 else if (msg->flags & winevent_hook)
1862 {
1863 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1864 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1865 }
1866 else
1867 {
1868 switch (msg->message)
1869 {
1870 case WM_WINDOWPOSCHANGING:
1871 case WM_WINDOWPOSCHANGED:
1872 {
1873 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1874
1875 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1876 msg->descr, msg->hwnd,
1877 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1878 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1879 winpos->x, winpos->y, winpos->cx, winpos->cy,
1880 get_winpos_flags(winpos->flags) );
1881
1882 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1883 * in the high word for internal purposes
1884 */
1885 seq->wParam = winpos->flags & 0xffff;
1886 /* We are not interested in the flags that don't match under XP and Win9x */
1887 seq->wParam &= ~SWP_NOZORDER;
1888 break;
1889 }
1890
1891 case WM_DRAWITEM:
1892 {
1893 DRAW_ITEM_STRUCT di;
1894 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1895
1896 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1897 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1898 dis->itemID, dis->itemAction, dis->itemState);
1899
1900 di.u.lp = 0;
1901 di.u.item.type = dis->CtlType;
1902 di.u.item.ctl_id = dis->CtlID;
1903 if (dis->CtlType == ODT_LISTBOX ||
1904 dis->CtlType == ODT_COMBOBOX ||
1905 dis->CtlType == ODT_MENU)
1906 di.u.item.item_id = dis->itemID;
1907 di.u.item.action = dis->itemAction;
1908 di.u.item.state = dis->itemState;
1909
1910 seq->lParam = di.u.lp;
1911 break;
1912 }
1913 default:
1914 if (msg->message >= 0xc000) return; /* ignore registered messages */
1915 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1916 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1917 }
1918 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1919 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1920 }
1921 }
1922
1923 sequence_cnt++;
1924 }
1925
1926 /* try to make sure pending X events have been processed before continuing */
1927 static void flush_events(void)
1928 {
1929 MSG msg;
1930 int diff = 200;
1931 int min_timeout = 100;
1932 DWORD time = GetTickCount() + diff;
1933
1934 while (diff > 0)
1935 {
1936 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1937 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
1938 diff = time - GetTickCount();
1939 }
1940 }
1941
1942 static void flush_sequence(void)
1943 {
1944 HeapFree(GetProcessHeap(), 0, sequence);
1945 sequence = 0;
1946 sequence_cnt = sequence_size = 0;
1947 }
1948
1949 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1950 {
1951 const struct recvd_message *actual = sequence;
1952 unsigned int count = 0;
1953
1954 trace_(file, line)("Failed sequence %s:\n", context );
1955 while (expected->message && actual->message)
1956 {
1957 if (actual->output[0])
1958 {
1959 if (expected->flags & hook)
1960 {
1961 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
1962 count, expected->message, actual->output );
1963 }
1964 else if (expected->flags & winevent_hook)
1965 {
1966 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
1967 count, expected->message, actual->output );
1968 }
1969 else if (expected->flags & kbd_hook)
1970 {
1971 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
1972 count, expected->message, actual->output );
1973 }
1974 else
1975 {
1976 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
1977 count, expected->message, actual->output );
1978 }
1979 }
1980
1981 if (expected->message == actual->message)
1982 {
1983 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1984 (expected->flags & optional))
1985 {
1986 /* don't match messages if their defwinproc status differs */
1987 expected++;
1988 }
1989 else
1990 {
1991 expected++;
1992 actual++;
1993 }
1994 }
1995 /* silently drop winevent messages if there is no support for them */
1996 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1997 expected++;
1998 else
1999 {
2000 expected++;
2001 actual++;
2002 }
2003 count++;
2004 }
2005
2006 /* optional trailing messages */
2007 while (expected->message && ((expected->flags & optional) ||
2008 ((expected->flags & winevent_hook) && !hEvent_hook)))
2009 {
2010 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2011 expected++;
2012 count++;
2013 }
2014
2015 if (expected->message)
2016 {
2017 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2018 return;
2019 }
2020
2021 while (actual->message && actual->output[0])
2022 {
2023 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2024 actual++;
2025 count++;
2026 }
2027 }
2028
2029 #define ok_sequence( exp, contx, todo) \
2030 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2031
2032
2033 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
2034 const char *file, int line)
2035 {
2036 static const struct recvd_message end_of_sequence;
2037 const struct message *expected = expected_list;
2038 const struct recvd_message *actual;
2039 int failcount = 0, dump = 0;
2040 unsigned int count = 0;
2041
2042 add_message(&end_of_sequence);
2043
2044 actual = sequence;
2045
2046 while (expected->message && actual->message)
2047 {
2048 if (expected->message == actual->message &&
2049 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2050 {
2051 if (expected->flags & wparam)
2052 {
2053 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2054 {
2055 todo_wine {
2056 failcount ++;
2057 if (strcmp(winetest_platform, "wine")) dump++;
2058 ok_( file, line) (FALSE,
2059 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2060 context, count, expected->message, expected->wParam, actual->wParam);
2061 }
2062 }
2063 else
2064 {
2065 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2066 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2067 context, count, expected->message, expected->wParam, actual->wParam);
2068 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2069 }
2070
2071 }
2072 if (expected->flags & lparam)
2073 {
2074 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2075 {
2076 todo_wine {
2077 failcount ++;
2078 if (strcmp(winetest_platform, "wine")) dump++;
2079 ok_( file, line) (FALSE,
2080 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2081 context, count, expected->message, expected->lParam, actual->lParam);
2082 }
2083 }
2084 else
2085 {
2086 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2087 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2088 context, count, expected->message, expected->lParam, actual->lParam);
2089 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2090 }
2091 }
2092 if ((expected->flags & optional) &&
2093 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2094 {
2095 /* don't match optional messages if their defwinproc or parent status differs */
2096 expected++;
2097 count++;
2098 continue;
2099 }
2100 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2101 {
2102 todo_wine {
2103 failcount ++;
2104 if (strcmp(winetest_platform, "wine")) dump++;
2105 ok_( file, line) (FALSE,
2106 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2107 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2108 }
2109 }
2110 else
2111 {
2112 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2113 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2114 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2115 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2116 }
2117
2118 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2119 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2120 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2121 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2122
2123 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2124 "%s: %u: the msg 0x%04x should have been %s\n",
2125 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2126 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2127
2128 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2129 "%s: %u: the msg 0x%04x was expected in %s\n",
2130 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2131 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2132
2133 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2134 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2135 context, count, expected->message);
2136 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2137
2138 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2139 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2140 context, count, expected->message);
2141 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2142
2143 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2144 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2145 context, count, expected->message);
2146 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2147
2148 expected++;
2149 actual++;
2150 }
2151 /* silently drop hook messages if there is no support for them */
2152 else if ((expected->flags & optional) ||
2153 ((expected->flags & hook) && !hCBT_hook) ||
2154 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2155 ((expected->flags & kbd_hook) && !hKBD_hook))
2156 expected++;
2157 else if (todo)
2158 {
2159 failcount++;
2160 todo_wine {
2161 if (strcmp(winetest_platform, "wine")) dump++;
2162 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2163 context, count, expected->message, actual->message);
2164 }
2165 goto done;
2166 }
2167 else
2168 {
2169 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2170 context, count, expected->message, actual->message);
2171 dump++;
2172 expected++;
2173 actual++;
2174 }
2175 count++;
2176 }
2177
2178 /* skip all optional trailing messages */
2179 while (expected->message && ((expected->flags & optional) ||
2180 ((expected->flags & hook) && !hCBT_hook) ||
2181 ((expected->flags & winevent_hook) && !hEvent_hook)))
2182 expected++;
2183
2184 if (todo)
2185 {
2186 todo_wine {
2187 if (expected->message || actual->message) {
2188 failcount++;
2189 if (strcmp(winetest_platform, "wine")) dump++;
2190 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2191 context, count, expected->message, actual->message);
2192 }
2193 }
2194 }
2195 else
2196 {
2197 if (expected->message || actual->message)
2198 {
2199 dump++;
2200 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2201 context, count, expected->message, actual->message);
2202 }
2203 }
2204 if( todo && !failcount) /* succeeded yet marked todo */
2205 todo_wine {
2206 if (!strcmp(winetest_platform, "wine")) dump++;
2207 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2208 }
2209
2210 done:
2211 if (dump) dump_sequence(expected_list, context, file, line);
2212 flush_sequence();
2213 }
2214
2215 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2216
2217 /******************************** MDI test **********************************/
2218
2219 /* CreateWindow for MDI frame window, initially visible */
2220 static const struct message WmCreateMDIframeSeq[] = {
2221 { HCBT_CREATEWND, hook },
2222 { WM_GETMINMAXINFO, sent },
2223 { WM_NCCREATE, sent },
2224 { WM_NCCALCSIZE, sent|wparam, 0 },
2225 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2226 { WM_CREATE, sent },
2227 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2228 { WM_NOTIFYFORMAT, sent|optional },
2229 { WM_QUERYUISTATE, sent|optional },
2230 { WM_WINDOWPOSCHANGING, sent|optional },
2231 { WM_GETMINMAXINFO, sent|optional },
2232 { WM_NCCALCSIZE, sent|optional },
2233 { WM_WINDOWPOSCHANGED, sent|optional },
2234 { WM_SHOWWINDOW, sent|wparam, 1 },
2235 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2236 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2237 { HCBT_ACTIVATE, hook },
2238 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2239 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2240 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2241 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2242 { WM_NCACTIVATE, sent },
2243 { WM_GETTEXT, sent|defwinproc|optional },
2244 { WM_ACTIVATE, sent|wparam, 1 },
2245 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2246 { HCBT_SETFOCUS, hook },
2247 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2248 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2249 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2250 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2251 /* Win9x adds SWP_NOZORDER below */
2252 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2253 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2254 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2255 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2256 { WM_MOVE, sent },
2257 { 0 }
2258 };
2259 /* DestroyWindow for MDI frame window, initially visible */
2260 static const struct message WmDestroyMDIframeSeq[] = {
2261 { HCBT_DESTROYWND, hook },
2262 { 0x0090, sent|optional },
2263 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2264 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2265 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2266 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2267 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2268 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2269 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2270 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2271 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2272 { WM_DESTROY, sent },
2273 { WM_NCDESTROY, sent },
2274 { 0 }
2275 };
2276 /* CreateWindow for MDI client window, initially visible */
2277 static const struct message WmCreateMDIclientSeq[] = {
2278 { HCBT_CREATEWND, hook },
2279 { WM_NCCREATE, sent },
2280 { WM_NCCALCSIZE, sent|wparam, 0 },
2281 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2282 { WM_CREATE, sent },
2283 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2284 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2285 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2286 { WM_MOVE, sent },
2287 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2288 { WM_SHOWWINDOW, sent|wparam, 1 },
2289 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2290 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2291 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2292 { 0 }
2293 };
2294 /* ShowWindow(SW_SHOW) for MDI client window */
2295 static const struct message WmShowMDIclientSeq[] = {
2296 { WM_SHOWWINDOW, sent|wparam, 1 },
2297 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2298 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2299 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2300 { 0 }
2301 };
2302 /* ShowWindow(SW_HIDE) for MDI client window */
2303 static const struct message WmHideMDIclientSeq[] = {
2304 { WM_SHOWWINDOW, sent|wparam, 0 },
2305 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2306 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2307 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2308 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2309 { 0 }
2310 };
2311 /* DestroyWindow for MDI client window, initially visible */
2312 static const struct message WmDestroyMDIclientSeq[] = {
2313 { HCBT_DESTROYWND, hook },
2314 { 0x0090, sent|optional },
2315 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2316 { WM_SHOWWINDOW, sent|wparam, 0 },
2317 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2318 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2319 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2320 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2321 { WM_DESTROY, sent },
2322 { WM_NCDESTROY, sent },
2323 { 0 }
2324 };
2325 /* CreateWindow for MDI child window, initially visible */
2326 static const struct message WmCreateMDIchildVisibleSeq[] = {
2327 { HCBT_CREATEWND, hook },
2328 { WM_NCCREATE, sent },
2329 { WM_NCCALCSIZE, sent|wparam, 0 },
2330 { WM_CREATE, sent },
2331 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2332 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2333 { WM_MOVE, sent },
2334 /* Win2k sends wparam set to
2335 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2336 * while Win9x doesn't bother to set child window id according to
2337 * CLIENTCREATESTRUCT.idFirstChild
2338 */
2339 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2340 { WM_SHOWWINDOW, sent|wparam, 1 },
2341 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2342 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2343 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2344 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2345 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2346 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2347 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2348
2349 /* Win9x: message sequence terminates here. */
2350
2351 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2352 { HCBT_SETFOCUS, hook }, /* in MDI client */
2353 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2354 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2355 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2356 { WM_SETFOCUS, sent }, /* in MDI client */
2357 { HCBT_SETFOCUS, hook },
2358 { WM_KILLFOCUS, sent }, /* in MDI client */
2359 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2360 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2361 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2362 { WM_SETFOCUS, sent|defwinproc },
2363 { WM_MDIACTIVATE, sent|defwinproc },
2364 { 0 }
2365 };
2366 /* CreateWindow for MDI child window with invisible parent */
2367 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2368 { HCBT_CREATEWND, hook },
2369 { WM_GETMINMAXINFO, sent },
2370 { WM_NCCREATE, sent },
2371 { WM_NCCALCSIZE, sent|wparam, 0 },
2372 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2373 { WM_CREATE, sent },
2374 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2375 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2376 { WM_MOVE, sent },
2377 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2378 { WM_SHOWWINDOW, sent|wparam, 1 },
2379 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2380 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2381 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2382 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2383
2384 /* Win9x: message sequence terminates here. */
2385
2386 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2387 { HCBT_SETFOCUS, hook }, /* in MDI client */
2388 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2389 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2390 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2391 { WM_SETFOCUS, sent }, /* in MDI client */
2392 { HCBT_SETFOCUS, hook },
2393 { WM_KILLFOCUS, sent }, /* in MDI client */
2394 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2395 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2396 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2397 { WM_SETFOCUS, sent|defwinproc },
2398 { WM_MDIACTIVATE, sent|defwinproc },
2399 { 0 }
2400 };
2401 /* DestroyWindow for MDI child window, initially visible */
2402 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2403 { HCBT_DESTROYWND, hook },
2404 /* Win2k sends wparam set to
2405 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2406 * while Win9x doesn't bother to set child window id according to
2407 * CLIENTCREATESTRUCT.idFirstChild
2408 */
2409 { 0x0090, sent|optional },
2410 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2411 { WM_SHOWWINDOW, sent|wparam, 0 },
2412 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2413 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2414 { WM_ERASEBKGND, sent|parent|optional },
2415 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2416
2417 /* { WM_DESTROY, sent }
2418 * Win9x: message sequence terminates here.
2419 */
2420
2421 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2422 { WM_KILLFOCUS, sent },
2423 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2424 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2425 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2426 { WM_SETFOCUS, sent }, /* in MDI client */
2427
2428 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2429 { WM_KILLFOCUS, sent }, /* in MDI client */
2430 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2431 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2432 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2433 { WM_SETFOCUS, sent }, /* in MDI client */
2434
2435 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2436
2437 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2438 { WM_KILLFOCUS, sent },
2439 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2440 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2441 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2442 { WM_SETFOCUS, sent }, /* in MDI client */
2443
2444 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2445 { WM_KILLFOCUS, sent }, /* in MDI client */
2446 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2447 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2448 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2449 { WM_SETFOCUS, sent }, /* in MDI client */
2450
2451 { WM_DESTROY, sent },
2452
2453 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2454 { WM_KILLFOCUS, sent },
2455 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2456 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2457 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2458 { WM_SETFOCUS, sent }, /* in MDI client */
2459
2460 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2461 { WM_KILLFOCUS, sent }, /* in MDI client */
2462 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2463 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2464 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2465 { WM_SETFOCUS, sent }, /* in MDI client */
2466
2467 { WM_NCDESTROY, sent },
2468 { 0 }
2469 };
2470 /* CreateWindow for MDI child window, initially invisible */
2471 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2472 { HCBT_CREATEWND, hook },
2473 { WM_NCCREATE, sent },
2474 { WM_NCCALCSIZE, sent|wparam, 0 },
2475 { WM_CREATE, sent },
2476 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2477 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2478 { WM_MOVE, sent },
2479 /* Win2k sends wparam set to
2480 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2481 * while Win9x doesn't bother to set child window id according to
2482 * CLIENTCREATESTRUCT.idFirstChild
2483 */
2484 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2485 { 0 }
2486 };
2487 /* DestroyWindow for MDI child window, initially invisible */
2488 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2489 { HCBT_DESTROYWND, hook },
2490 /* Win2k sends wparam set to
2491 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2492 * while Win9x doesn't bother to set child window id according to
2493 * CLIENTCREATESTRUCT.idFirstChild
2494 */
2495 { 0x0090, sent|optional },
2496 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2497 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2498 { WM_DESTROY, sent },
2499 { WM_NCDESTROY, sent },
2500 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2501 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2502 { 0 }
2503 };
2504 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2505 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2506 { HCBT_CREATEWND, hook },
2507 { WM_NCCREATE, sent },
2508 { WM_NCCALCSIZE, sent|wparam, 0 },
2509 { WM_CREATE, sent },
2510 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2511 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2512 { WM_MOVE, sent },
2513 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2514 { WM_GETMINMAXINFO, sent },
2515 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2516 { WM_NCCALCSIZE, sent|wparam, 1 },
2517 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2518 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2519 /* in MDI frame */
2520 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2521 { WM_NCCALCSIZE, sent|wparam, 1 },
2522 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2523 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2524 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2525 /* Win2k sends wparam set to
2526 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2527 * while Win9x doesn't bother to set child window id according to
2528 * CLIENTCREATESTRUCT.idFirstChild
2529 */
2530 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2531 { WM_SHOWWINDOW, sent|wparam, 1 },
2532 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2533 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2534 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2535 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2536 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2537 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2538 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2539
2540 /* Win9x: message sequence terminates here. */
2541
2542 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2543 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2544 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2545 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2546 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2547 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2548 { HCBT_SETFOCUS, hook|optional },
2549 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2550 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2551 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2552 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2553 { WM_SETFOCUS, sent|defwinproc|optional },
2554 { WM_MDIACTIVATE, sent|defwinproc|optional },
2555 /* in MDI frame */
2556 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2557 { WM_NCCALCSIZE, sent|wparam, 1 },
2558 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2559 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2560 { 0 }
2561 };
2562 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2563 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2564 /* restore the 1st MDI child */
2565 { WM_SETREDRAW, sent|wparam, 0 },
2566 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2567 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2568 { WM_NCCALCSIZE, sent|wparam, 1 },
2569 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2570 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2571 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2572 /* in MDI frame */
2573 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2574 { WM_NCCALCSIZE, sent|wparam, 1 },
2575 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2576 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2577 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2578 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2579 /* create the 2nd MDI child */
2580 { HCBT_CREATEWND, hook },
2581 { WM_NCCREATE, sent },
2582 { WM_NCCALCSIZE, sent|wparam, 0 },
2583 { WM_CREATE, sent },
2584 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2585 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2586 { WM_MOVE, sent },
2587 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2588 { WM_GETMINMAXINFO, sent },
2589 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2590 { WM_NCCALCSIZE, sent|wparam, 1 },
2591 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2592 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2593 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2594 /* in MDI frame */
2595 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2596 { WM_NCCALCSIZE, sent|wparam, 1 },
2597 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2598 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2599 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2600 /* Win2k sends wparam set to
2601 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2602 * while Win9x doesn't bother to set child window id according to
2603 * CLIENTCREATESTRUCT.idFirstChild
2604 */
2605 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2606 { WM_SHOWWINDOW, sent|wparam, 1 },
2607 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2608 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2609 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2610 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2611 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2612 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2613
2614 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2615 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2616
2617 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2618
2619 /* Win9x: message sequence terminates here. */
2620
2621 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2622 { HCBT_SETFOCUS, hook },
2623 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2624 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2625 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2626 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2627 { WM_SETFOCUS, sent }, /* in MDI client */
2628 { HCBT_SETFOCUS, hook },
2629 { WM_KILLFOCUS, sent }, /* in MDI client */
2630 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2631 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2632 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2633 { WM_SETFOCUS, sent|defwinproc },
2634
2635 { WM_MDIACTIVATE, sent|defwinproc },
2636 /* in MDI frame */
2637 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2638 { WM_NCCALCSIZE, sent|wparam, 1 },
2639 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2640 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2641 { 0 }
2642 };
2643 /* WM_MDICREATE MDI child window, initially visible and maximized */
2644 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2645 { WM_MDICREATE, sent },
2646 { HCBT_CREATEWND, hook },
2647 { WM_NCCREATE, sent },
2648 { WM_NCCALCSIZE, sent|wparam, 0 },
2649 { WM_CREATE, sent },
2650 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2651 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2652 { WM_MOVE, sent },
2653 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2654 { WM_GETMINMAXINFO, sent },
2655 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2656 { WM_NCCALCSIZE, sent|wparam, 1 },
2657 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2658 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2659
2660 /* in MDI frame */
2661 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2662 { WM_NCCALCSIZE, sent|wparam, 1 },
2663 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2664 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2665 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2666
2667 /* Win2k sends wparam set to
2668 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2669 * while Win9x doesn't bother to set child window id according to
2670 * CLIENTCREATESTRUCT.idFirstChild
2671 */
2672 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2673 { WM_SHOWWINDOW, sent|wparam, 1 },
2674 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2675
2676 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2677
2678 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2679 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2680 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2681
2682 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2683 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2684
2685 /* Win9x: message sequence terminates here. */
2686
2687 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2688 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2689 { HCBT_SETFOCUS, hook }, /* in MDI client */
2690 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2691 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2692 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2693 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2694 { HCBT_SETFOCUS, hook|optional },
2695 { WM_KILLFOCUS, sent }, /* in MDI client */
2696 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2697 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2698 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2699 { WM_SETFOCUS, sent|defwinproc },
2700
2701 { WM_MDIACTIVATE, sent|defwinproc },
2702
2703 /* in MDI child */
2704 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2705 { WM_NCCALCSIZE, sent|wparam, 1 },
2706 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2707 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2708
2709 /* in MDI frame */
2710 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2711 { WM_NCCALCSIZE, sent|wparam, 1 },
2712 { 0x0093, sent|defwinproc|optional },
2713 { 0x0093, sent|defwinproc|optional },
2714 { 0x0093, sent|defwinproc|optional },
2715 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2716 { WM_MOVE, sent|defwinproc },
2717 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2718
2719 /* in MDI client */
2720 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2721 { WM_NCCALCSIZE, sent|wparam, 1 },
2722 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2723 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2724
2725 /* in MDI child */
2726 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2727 { WM_NCCALCSIZE, sent|wparam, 1 },
2728 { 0x0093, sent|optional },
2729 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2730 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2731
2732 { 0x0093, sent|optional },
2733 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2734 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2735 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2736 { 0x0093, sent|defwinproc|optional },
2737 { 0x0093, sent|defwinproc|optional },
2738 { 0x0093, sent|defwinproc|optional },
2739 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2740 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2741
2742 { 0 }
2743 };
2744 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2745 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2746 { HCBT_CREATEWND, hook },
2747 { WM_GETMINMAXINFO, sent },
2748 { WM_NCCREATE, sent },
2749 { WM_NCCALCSIZE, sent|wparam, 0 },
2750 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2751 { WM_CREATE, sent },
2752 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2753 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2754 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2755 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2756 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2757 { WM_MOVE, sent },
2758 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2759 { WM_GETMINMAXINFO, sent },
2760 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2761 { WM_GETMINMAXINFO, sent|defwinproc },
2762 { WM_NCCALCSIZE, sent|wparam, 1 },
2763 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
2764 { WM_MOVE, sent|defwinproc },
2765 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2766 /* in MDI frame */
2767 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2768 { WM_NCCALCSIZE, sent|wparam, 1 },
2769 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2770 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2771 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2772 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2773 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2774 /* Win2k sends wparam set to
2775 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2776 * while Win9x doesn't bother to set child window id according to
2777 * CLIENTCREATESTRUCT.idFirstChild
2778 */
2779 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2780 { 0 }
2781 };
2782 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2783 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2784 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2785 { HCBT_SYSCOMMAND, hook },
2786 { WM_CLOSE, sent|defwinproc },
2787 { WM_MDIDESTROY, sent }, /* in MDI client */
2788
2789 /* bring the 1st MDI child to top */
2790 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2791 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2792
2793 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2794
2795 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2796 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2797 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2798
2799 /* maximize the 1st MDI child */
2800 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2801 { WM_GETMINMAXINFO, sent|defwinproc },
2802 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2803 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2804 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2805 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2806 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2807
2808 /* restore the 2nd MDI child */
2809 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2810 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2811 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2812 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2813
2814 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2815
2816 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2817 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2818
2819 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2820
2821 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2822 /* in MDI frame */
2823 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2824 { WM_NCCALCSIZE, sent|wparam, 1 },
2825 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2826 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2827 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2828
2829 /* bring the 1st MDI child to top */
2830 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2831 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2832 { HCBT_SETFOCUS, hook },
2833 { WM_KILLFOCUS, sent|defwinproc },
2834 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2835 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2836 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2837 { WM_SETFOCUS, sent }, /* in MDI client */
2838 { HCBT_SETFOCUS, hook },
2839 { WM_KILLFOCUS, sent }, /* in MDI client */
2840 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2841 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2842 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2843 { WM_SETFOCUS, sent|defwinproc },
2844 { WM_MDIACTIVATE, sent|defwinproc },
2845 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2846
2847 /* apparently ShowWindow(SW_SHOW) on an MDI client */
2848 { WM_SHOWWINDOW, sent|wparam, 1 },
2849 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2850 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2851 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2852 { WM_MDIREFRESHMENU, sent },
2853
2854 { HCBT_DESTROYWND, hook },
2855 /* Win2k sends wparam set to
2856 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2857 * while Win9x doesn't bother to set child window id according to
2858 * CLIENTCREATESTRUCT.idFirstChild
2859 */
2860 { 0x0090, sent|defwinproc|optional },
2861 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2862 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2863 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2864 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2865 { WM_ERASEBKGND, sent|parent|optional },
2866 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2867
2868 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2869 { WM_DESTROY, sent|defwinproc },
2870 { WM_NCDESTROY, sent|defwinproc },
2871 { 0 }
2872 };
2873 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2874 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2875 { WM_MDIDESTROY, sent }, /* in MDI client */
2876 { WM_SHOWWINDOW, sent|wparam, 0 },
2877 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2878 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2879 { WM_ERASEBKGND, sent|parent|optional },
2880 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2881
2882 { HCBT_SETFOCUS, hook },
2883 { WM_KILLFOCUS, sent },
2884 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2885 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2886 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2887 { WM_SETFOCUS, sent }, /* in MDI client */
2888 { HCBT_SETFOCUS, hook },
2889 { WM_KILLFOCUS, sent }, /* in MDI client */
2890 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2891 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2892 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2893 { WM_SETFOCUS, sent },
2894
2895 /* in MDI child */
2896 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2897 { WM_NCCALCSIZE, sent|wparam, 1 },
2898 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2899 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2900
2901 /* in MDI frame */
2902 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2903 { WM_NCCALCSIZE, sent|wparam, 1 },
2904 { 0x0093, sent|defwinproc|optional },
2905 { 0x0093, sent|defwinproc|optional },
2906 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2907 { WM_MOVE, sent|defwinproc },
2908 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2909
2910 /* in MDI client */
2911 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2912 { WM_NCCALCSIZE, sent|wparam, 1 },
2913 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2914 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2915
2916 /* in MDI child */
2917 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2918 { WM_NCCALCSIZE, sent|wparam, 1 },
2919 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2920 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2921
2922 /* in MDI child */
2923 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2924 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2925 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2926 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2927
2928 /* in MDI frame */
2929 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2930 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2931 { 0x0093, sent|defwinproc|optional },
2932 { 0x0093, sent|defwinproc|optional },
2933 { 0x0093, sent|defwinproc|optional },
2934 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2935 { WM_MOVE, sent|defwinproc },
2936 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2937
2938 /* in MDI client */
2939 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2940 { WM_NCCALCSIZE, sent|wparam, 1 },
2941 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2942 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2943
2944 /* in MDI child */
2945 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2946 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2947 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2948 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2949 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2950 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2951
2952 { 0x0093, sent|defwinproc|optional },
2953 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2954 { 0x0093, sent|defwinproc|optional },
2955 { 0x0093, sent|defwinproc|optional },
2956 { 0x0093, sent|defwinproc|optional },
2957 { 0x0093, sent|optional },
2958
2959 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2960 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2961 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2962 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2963 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2964
2965 /* in MDI frame */
2966 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2967 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2968 { 0x0093, sent|defwinproc|optional },
2969 { 0x0093, sent|defwinproc|optional },
2970 { 0x0093, sent|defwinproc|optional },
2971 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2972 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2973 { 0x0093, sent|optional },
2974
2975 { WM_NCACTIVATE, sent|wparam, 0 },
2976 { WM_MDIACTIVATE, sent },
2977
2978 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2979 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2980 { WM_NCCALCSIZE, sent|wparam, 1 },
2981
2982 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2983
2984 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2985 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2986 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2987
2988 /* in MDI child */
2989 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2990 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2991 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2992 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2993
2994 /* in MDI frame */
2995 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2996 { WM_NCCALCSIZE, sent|wparam, 1 },
2997 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2998 { WM_MOVE, sent|defwinproc },
2999 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3000
3001 /* in MDI client */
3002 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3003 { WM_NCCALCSIZE, sent|wparam, 1 },
3004 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3005 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3006 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3007 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3008 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3009 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3010 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3011
3012 { HCBT_SETFOCUS, hook },
3013 { WM_KILLFOCUS, sent },
3014 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3015 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3016 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3017 { WM_SETFOCUS, sent }, /* in MDI client */
3018
3019 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3020
3021 { HCBT_DESTROYWND, hook },
3022 /* Win2k sends wparam set to
3023 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3024 * while Win9x doesn't bother to set child window id according to
3025 * CLIENTCREATESTRUCT.idFirstChild
3026 */
3027 { 0x0090, sent|optional },
3028 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3029
3030 { WM_SHOWWINDOW, sent|wparam, 0 },
3031 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3032 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3033 { WM_ERASEBKGND, sent|parent|optional },
3034 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3035
3036 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3037 { WM_DESTROY, sent },
3038 { WM_NCDESTROY, sent },
3039 { 0 }
3040 };
3041 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3042 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3043 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3044 { WM_GETMINMAXINFO, sent },
3045 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3046 { WM_NCCALCSIZE, sent|wparam, 1 },
3047 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3048 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3049
3050 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3051 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3052 { HCBT_SETFOCUS, hook|optional },
3053 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3054 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3055 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3056 { HCBT_SETFOCUS, hook|optional },
3057 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3058 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3059 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3060 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3061 { WM_SETFOCUS, sent|optional|defwinproc },
3062 { WM_MDIACTIVATE, sent|optional|defwinproc },
3063 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3064 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3065 /* in MDI frame */
3066 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3067 { WM_NCCALCSIZE, sent|wparam, 1 },
3068 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3069 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3070 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3071 { 0 }
3072 };
3073 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3074 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3075 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3076 { WM_GETMINMAXINFO, sent },
3077 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3078 { WM_GETMINMAXINFO, sent|defwinproc },
3079 { WM_NCCALCSIZE, sent|wparam, 1 },
3080 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3081 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3082
3083 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3084 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3085 { HCBT_SETFOCUS, hook|optional },
3086 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3087 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3088 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3089 { HCBT_SETFOCUS, hook|optional },
3090 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3091 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3092 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3093 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3094 { WM_SETFOCUS, sent|defwinproc|optional },
3095 { WM_MDIACTIVATE, sent|defwinproc|optional },
3096 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3097 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3098 { 0 }
3099 };
3100 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3101 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3102 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3103 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3104 { WM_GETMINMAXINFO, sent },
3105 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3106 { WM_GETMINMAXINFO, sent|defwinproc },
3107 { WM_NCCALCSIZE, sent|wparam, 1 },
3108 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3109 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3110 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3111 { WM_MOVE, sent|defwinproc },
3112 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3113
3114 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3115 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3116 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3117 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3118 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3119 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3120 /* in MDI frame */
3121 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3122 { WM_NCCALCSIZE, sent|wparam, 1 },
3123 { 0x0093, sent|defwinproc|optional },
3124 { 0x0094, sent|defwinproc|optional },
3125 { 0x0094, sent|defwinproc|optional },
3126 { 0x0094, sent|defwinproc|optional },
3127 { 0x0094, sent|defwinproc|optional },
3128 { 0x0093, sent|defwinproc|optional },
3129 { 0x0093, sent|defwinproc|optional },
3130 { 0x0091, sent|defwinproc|optional },
3131 { 0x0092, sent|defwinproc|optional },
3132 { 0x0092, sent|defwinproc|optional },
3133 { 0x0092, sent|defwinproc|optional },
3134 { 0x0092, sent|defwinproc|optional },
3135 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3136 { WM_MOVE, sent|defwinproc },
3137 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3138 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3139 /* in MDI client */
3140 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3141 { WM_NCCALCSIZE, sent|wparam, 1 },
3142 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3143 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3144 /* in MDI child */
3145 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3146 { WM_GETMINMAXINFO, sent|defwinproc },
3147 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3148 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3149 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3150 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3151 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3152 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3153 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3154 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3155 /* in MDI frame */
3156 { 0x0093, sent|optional },
3157 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3158 { 0x0093, sent|defwinproc|optional },
3159 { 0x0093, sent|defwinproc|optional },
3160 { 0x0093, sent|defwinproc|optional },
3161 { 0x0091, sent|defwinproc|optional },
3162 { 0x0092, sent|defwinproc|optional },
3163 { 0x0092, sent|defwinproc|optional },
3164 { 0x0092, sent|defwinproc|optional },
3165 { 0x0092, sent|defwinproc|optional },
3166 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3167 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3168 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3169 { 0 }
3170 };
3171 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3172 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3173 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3174 { WM_GETMINMAXINFO, sent },
3175 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3176 { WM_NCCALCSIZE, sent|wparam, 1 },
3177 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3178 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3179 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3180 /* in MDI frame */
3181 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3182 { WM_NCCALCSIZE, sent|wparam, 1 },
3183 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3184 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3185 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3186 { 0 }
3187 };
3188 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3189 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3190 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3191 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3192 { WM_NCCALCSIZE, sent|wparam, 1 },
3193 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3194 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3195 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3196 /* in MDI frame */
3197 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3198 { WM_NCCALCSIZE, sent|wparam, 1 },
3199 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3200 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3201 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3202 { 0 }
3203 };
3204 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3205 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3206 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3207 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3208 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3209 { WM_NCCALCSIZE, sent|wparam, 1 },
3210 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3211 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3212 { WM_MOVE, sent|defwinproc },
3213 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3214 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3215 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3216 { HCBT_SETFOCUS, hook },
3217 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3218 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3219 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3220 { WM_SETFOCUS, sent },
3221 { 0 }
3222 };
3223 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3224 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3225 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3226 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3227 { WM_NCCALCSIZE, sent|wparam, 1 },
3228 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3229 { WM_MOVE, sent|defwinproc },
3230 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3231 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3232 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3233 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3234 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3235 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3236 { 0 }
3237 };
3238 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3239 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3240 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3241 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3242 { WM_NCCALCSIZE, sent|wparam, 1 },
3243 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3244 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3245 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3246 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3247 /* in MDI frame */
3248 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3249 { WM_NCCALCSIZE, sent|wparam, 1 },
3250 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3251 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3252 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3253 { 0 }
3254 };
3255
3256 static HWND mdi_client;
3257 static WNDPROC old_mdi_client_proc;
3258
3259 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3260 {
3261 struct recvd_message msg;
3262
3263 /* do not log painting messages */
3264 if (message != WM_PAINT &&
3265 message != WM_NCPAINT &&
3266 message != WM_SYNCPAINT &&
3267 message != WM_ERASEBKGND &&
3268 message != WM_NCHITTEST &&
3269 message != WM_GETTEXT &&
3270 message != WM_MDIGETACTIVE &&
3271 !ignore_message( message ))
3272 {
3273 msg.hwnd = hwnd;
3274 msg.message = message;
3275 msg.flags = sent|wparam|lparam;
3276 msg.wParam = wParam;
3277 msg.lParam = lParam;
3278 msg.descr = "mdi client";
3279 add_message(&msg);
3280 }
3281
3282 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3283 }
3284
3285 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3286 {
3287 static LONG defwndproc_counter = 0;
3288 LRESULT ret;
3289 struct recvd_message msg;
3290
3291 /* do not log painting messages */
3292 if (message != WM_PAINT &&
3293 message != WM_NCPAINT &&
3294 message != WM_SYNCPAINT &&
3295 message != WM_ERASEBKGND &&
3296 message != WM_NCHITTEST &&
3297 message != WM_GETTEXT &&
3298 !ignore_message( message ))
3299 {
3300 switch (message)
3301 {
3302 case WM_MDIACTIVATE:
3303 {
3304 HWND active, client = GetParent(hwnd);
3305
3306 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3307
3308 if (hwnd == (HWND)lParam) /* if we are being activated */
3309 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3310 else
3311 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3312 break;
3313 }
3314 }
3315
3316 msg.hwnd = hwnd;
3317 msg.message = message;
3318 msg.flags = sent|wparam|lparam;
3319 if (defwndproc_counter) msg.flags |= defwinproc;
3320 msg.wParam = wParam;
3321 msg.lParam = lParam;
3322 msg.descr = "mdi child";
3323 add_message(&msg);
3324 }
3325
3326 defwndproc_counter++;
3327 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3328 defwndproc_counter--;
3329
3330 return ret;
3331 }
3332
3333 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3334 {
3335 static LONG defwndproc_counter = 0;
3336 LRESULT ret;
3337 struct recvd_message msg;
3338
3339 /* do not log painting messages */
3340 if (message != WM_PAINT &&
3341 message != WM_NCPAINT &&
3342 message != WM_SYNCPAINT &&
3343 message != WM_ERASEBKGND &&
3344 message != WM_NCHITTEST &&
3345 message != WM_GETTEXT &&
3346 !ignore_message( message ))
3347 {
3348 msg.hwnd = hwnd;
3349 msg.message = message;
3350 msg.flags = sent|wparam|lparam;
3351 if (defwndproc_counter) msg.flags |= defwinproc;
3352 msg.wParam = wParam;
3353 msg.lParam = lParam;
3354 msg.descr = "mdi frame";
3355 add_message(&msg);
3356 }
3357
3358 defwndproc_counter++;
3359 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3360 defwndproc_counter--;
3361
3362 return ret;
3363 }
3364
3365 static BOOL mdi_RegisterWindowClasses(void)
3366 {
3367 WNDCLASSA cls;
3368
3369 cls.style = 0;
3370 cls.lpfnWndProc = mdi_frame_wnd_proc;
3371 cls.cbClsExtra = 0;
3372 cls.cbWndExtra = 0;
3373 cls.hInstance = GetModuleHandleA(0);
3374 cls.hIcon = 0;
3375 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3376 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3377 cls.lpszMenuName = NULL;
3378 cls.lpszClassName = "MDI_frame_class";
3379 if (!RegisterClassA(&cls)) return FALSE;
3380
3381 cls.lpfnWndProc = mdi_child_wnd_proc;
3382 cls.lpszClassName = "MDI_child_class";
3383 if (!RegisterClassA(&cls)) return FALSE;
3384
3385 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3386 old_mdi_client_proc = cls.lpfnWndProc;
3387 cls.hInstance = GetModuleHandleA(0);
3388 cls.lpfnWndProc = mdi_client_hook_proc;
3389 cls.lpszClassName = "MDI_client_class";
3390 if (!RegisterClassA(&cls)) assert(0);
3391
3392 return TRUE;
3393 }
3394
3395 static void test_mdi_messages(void)
3396 {
3397 MDICREATESTRUCTA mdi_cs;
3398 CLIENTCREATESTRUCT client_cs;
3399 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3400 BOOL zoomed;
3401 RECT rc;
3402 HMENU hMenu = CreateMenu();
3403
3404 if (!mdi_RegisterWindowClasses()) assert(0);
3405
3406 flush_sequence();
3407
3408 trace("creating MDI frame window\n");
3409 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3410 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3411 WS_MAXIMIZEBOX | WS_VISIBLE,
3412 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3413 GetDesktopWindow(), hMenu,
3414 GetModuleHandleA(0), NULL);
3415 assert(mdi_frame);
3416 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3417
3418 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3419 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3420
3421 trace("creating MDI client window\n");
3422 GetClientRect(mdi_frame, &rc);
3423 client_cs.hWindowMenu = 0;
3424 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3425 mdi_client = CreateWindowExA(0, "MDI_client_class",
3426 NULL,
3427 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3428 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3429 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3430 assert(mdi_client);
3431 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3432
3433 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3434 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3435
3436 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3437 ok(!active_child, "wrong active MDI child %p\n", active_child);
3438 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3439
3440 SetFocus(0);
3441 flush_sequence();
3442
3443 trace("creating invisible MDI child window\n");
3444 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3445 WS_CHILD,
3446 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3447 mdi_client, 0, GetModuleHandleA(0), NULL);
3448 assert(mdi_child);
3449
3450 flush_sequence();
3451 ShowWindow(mdi_child, SW_SHOWNORMAL);
3452 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3453
3454 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3455 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3456
3457 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3458 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3459
3460 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3461 ok(!active_child, "wrong active MDI child %p\n", active_child);
3462 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3463
3464 ShowWindow(mdi_child, SW_HIDE);
3465 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3466 flush_sequence();
3467
3468 ShowWindow(mdi_child, SW_SHOW);
3469 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3470
3471 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3472 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3473
3474 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3475 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3476
3477 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3478 ok(!active_child, "wrong active MDI child %p\n", active_child);
3479 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3480
3481 DestroyWindow(mdi_child);
3482 flush_sequence();
3483
3484 trace("creating visible MDI child window\n");
3485 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3486 WS_CHILD | WS_VISIBLE,
3487 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3488 mdi_client, 0, GetModuleHandleA(0), NULL);
3489 assert(mdi_child);
3490 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3491
3492 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3493 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3494
3495 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3496 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3497
3498 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3499 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3500 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3501 flush_sequence();
3502
3503 DestroyWindow(mdi_child);
3504 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3505
3506 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3507 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3508
3509 /* Win2k: MDI client still returns a just destroyed child as active
3510 * Win9x: MDI client returns 0
3511 */
3512 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3513 ok(active_child == mdi_child || /* win2k */
3514 !active_child, /* win9x */
3515 "wrong active MDI child %p\n", active_child);
3516 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3517
3518 flush_sequence();
3519
3520 trace("creating invisible MDI child window\n");
3521 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3522 WS_CHILD,
3523 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3524 mdi_client, 0, GetModuleHandleA(0), NULL);
3525 assert(mdi_child2);
3526 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3527
3528 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3529 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3530
3531 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3532 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3533
3534 /* Win2k: MDI client still returns a just destroyed child as active
3535 * Win9x: MDI client returns mdi_child2
3536 */
3537 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3538 ok(active_child == mdi_child || /* win2k */
3539 active_child == mdi_child2, /* win9x */
3540 "wrong active MDI child %p\n", active_child);
3541 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3542 flush_sequence();
3543
3544 ShowWindow(mdi_child2, SW_MAXIMIZE);
3545 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3546
3547 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3548 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3549
3550 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3551 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3552 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3553 flush_sequence();
3554
3555 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3556 ok(GetFocus() == mdi_child2 || /* win2k */
3557 GetFocus() == 0, /* win9x */
3558 "wrong focus window %p\n", GetFocus());
3559
3560 SetFocus(0);
3561 flush_sequence();
3562
3563 ShowWindow(mdi_child2, SW_HIDE);
3564 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3565
3566 ShowWindow(mdi_child2, SW_RESTORE);
3567 ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3568 flush_sequence();
3569
3570 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3571 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3572
3573 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3574 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3575 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3576 flush_sequence();
3577
3578 SetFocus(0);
3579 flush_sequence();
3580
3581 ShowWindow(mdi_child2, SW_HIDE);
3582 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3583
3584 ShowWindow(mdi_child2, SW_SHOW);
3585 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3586
3587 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3588 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3589
3590 ShowWindow(mdi_child2, SW_MAXIMIZE);
3591 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3592
3593 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3594 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3595
3596 ShowWindow(mdi_child2, SW_RESTORE);
3597 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3598
3599 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3600 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3601
3602 ShowWindow(mdi_child2, SW_MINIMIZE);
3603 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3604
3605 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3606 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3607
3608 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3609 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3610 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3611 flush_sequence();
3612
3613 ShowWindow(mdi_child2, SW_RESTORE);
3614 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3615
3616 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3617 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3618
3619 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3620 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3621 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3622 flush_sequence();
3623
3624 SetFocus(0);
3625 flush_sequence();
3626
3627 ShowWindow(mdi_child2, SW_HIDE);
3628 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3629
3630 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3631 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3632
3633 DestroyWindow(mdi_child2);
3634 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3635
3636 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3637 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3638
3639 /* test for maximized MDI children */
3640 trace("creating maximized visible MDI child window 1\n");
3641 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3642 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3643 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3644 mdi_client, 0, GetModuleHandleA(0), NULL);
3645 assert(mdi_child);
3646 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3647 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3648
3649 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3650 ok(GetFocus() == mdi_child || /* win2k */
3651 GetFocus() == 0, /* win9x */
3652 "wrong focus window %p\n", GetFocus());
3653
3654 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3655 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3656 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3657 flush_sequence();
3658
3659 trace("creating maximized visible MDI child window 2\n");
3660 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3661 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3662 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3663 mdi_client, 0, GetModuleHandleA(0), NULL);
3664 assert(mdi_child2);
3665 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3666 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3667 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3668
3669 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3670 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3671
3672 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3673 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3674 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3675 flush_sequence();
3676
3677 trace("destroying maximized visible MDI child window 2\n");
3678 DestroyWindow(mdi_child2);
3679 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3680
3681 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3682
3683 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3684 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3685
3686 /* Win2k: MDI client still returns a just destroyed child as active
3687 * Win9x: MDI client returns 0
3688 */
3689 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3690 ok(active_child == mdi_child2 || /* win2k */
3691 !active_child, /* win9x */
3692 "wrong active MDI child %p\n", active_child);
3693 flush_sequence();
3694
3695 ShowWindow(mdi_child, SW_MAXIMIZE);
3696 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3697 flush_sequence();
3698
3699 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3700 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3701
3702 trace("re-creating maximized visible MDI child window 2\n");
3703 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3704 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3705 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3706 mdi_client, 0, GetModuleHandleA(0), NULL);
3707 assert(mdi_child2);
3708 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3709 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3710 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3711
3712 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3713 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3714
3715 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3716 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3717 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3718 flush_sequence();
3719
3720 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3721 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3722 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3723
3724 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3725 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3726 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3727
3728 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3729 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3730 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3731 flush_sequence();
3732
3733 DestroyWindow(mdi_child);
3734 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3735
3736 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3737 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3738
3739 /* Win2k: MDI client still returns a just destroyed child as active
3740 * Win9x: MDI client returns 0
3741 */
3742 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3743 ok(active_child == mdi_child || /* win2k */
3744 !active_child, /* win9x */
3745 "wrong active MDI child %p\n", active_child);
3746 flush_sequence();
3747
3748 trace("creating maximized invisible MDI child window\n");
3749 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3750 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3751 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3752 mdi_client, 0, GetModuleHandleA(0), NULL);
3753 assert(mdi_child2);
3754 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3755 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3756 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3757 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3758
3759 /* Win2k: MDI client still returns a just destroyed child as active
3760 * Win9x: MDI client returns 0
3761 */
3762 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3763 ok(active_child == mdi_child || /* win2k */
3764 !active_child || active_child == mdi_child2, /* win9x */
3765 "wrong active MDI child %p\n", active_child);
3766 flush_sequence();
3767
3768 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3769 ShowWindow(mdi_child2, SW_MAXIMIZE);
3770 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3771 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3772 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3773 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3774
3775 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3776 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3777 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3778 flush_sequence();
3779
3780 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3781 flush_sequence();
3782
3783 /* end of test for maximized MDI children */
3784 SetFocus(0);
3785 flush_sequence();
3786 trace("creating maximized visible MDI child window 1(Switch test)\n");
3787 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3788 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3789 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3790 mdi_client, 0, GetModuleHandleA(0), NULL);
3791 assert(mdi_child);
3792 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3793 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3794
3795 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3796 ok(GetFocus() == mdi_child || /* win2k */
3797 GetFocus() == 0, /* win9x */
3798 "wrong focus window %p(Switch test)\n", GetFocus());
3799
3800 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3801 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3802 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3803 flush_sequence();
3804
3805 trace("creating maximized visible MDI child window 2(Switch test)\n");
3806 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3807 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3808 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3809 mdi_client, 0, GetModuleHandleA(0), NULL);
3810 assert(mdi_child2);
3811 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3812
3813 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3814 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3815
3816 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3817 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3818
3819 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3820 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3821 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3822 flush_sequence();
3823
3824 trace("Switch child window.\n");
3825 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3826 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3827 trace("end of test for switch maximized MDI children\n");
3828 flush_sequence();
3829
3830 /* Prepare for switching test of not maximized MDI children */
3831 ShowWindow( mdi_child, SW_NORMAL );
3832 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3833 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3834 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3835 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3836 flush_sequence();
3837
3838 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3839 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3840 trace("end of test for switch not maximized MDI children\n");
3841 flush_sequence();
3842
3843 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3844 flush_sequence();
3845
3846 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3847 flush_sequence();
3848
3849 SetFocus(0);
3850 flush_sequence();
3851 /* end of tests for switch maximized/not maximized MDI children */
3852
3853 mdi_cs.szClass = "MDI_child_Class";
3854 mdi_cs.szTitle = "MDI child";
3855 mdi_cs.hOwner = GetModuleHandleA(0);
3856 mdi_cs.x = 0;
3857 mdi_cs.y = 0;
3858 mdi_cs.cx = CW_USEDEFAULT;
3859 mdi_cs.cy = CW_USEDEFAULT;
3860 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3861 mdi_cs.lParam = 0;
3862 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3863 ok(mdi_child != 0, "MDI child creation failed\n");
3864 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3865
3866 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3867
3868 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3869 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3870
3871 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3872 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3873 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3874
3875 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3876 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3877 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3878 flush_sequence();
3879
3880 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3881 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3882
3883 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3884 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3885 ok(!active_child, "wrong active MDI child %p\n", active_child);
3886
3887 SetFocus(0);
3888 flush_sequence();
3889
3890 DestroyWindow(mdi_client);
3891 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3892
3893 /* test maximization of MDI child with invisible parent */
3894 client_cs.hWindowMenu = 0;
3895 mdi_client = CreateWindowA("MDI_client_class",
3896 NULL,
3897 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3898 0, 0, 660, 430,
3899 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3900 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3901
3902 ShowWindow(mdi_client, SW_HIDE);
3903 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3904
3905 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3906 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3907 0, 0, 650, 440,
3908 mdi_client, 0, GetModuleHandleA(0), NULL);
3909 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3910
3911 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3912 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3913 zoomed = IsZoomed(mdi_child);
3914 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3915
3916 ShowWindow(mdi_client, SW_SHOW);
3917 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3918
3919 DestroyWindow(mdi_child);
3920 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3921
3922 /* end of test for maximization of MDI child with invisible parent */
3923
3924 DestroyWindow(mdi_client);
3925 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3926
3927 DestroyWindow(mdi_frame);
3928 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3929 }
3930 /************************* End of MDI test **********************************/
3931
3932 static void test_WM_SETREDRAW(HWND hwnd)
3933 {
3934 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3935
3936 flush_events();
3937 flush_sequence();
3938
3939 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3940 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3941
3942 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3943 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3944
3945 flush_sequence();
3946 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3947 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3948
3949 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3950 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3951
3952 /* restore original WS_VISIBLE state */
3953 SetWindowLongA(hwnd, GWL_STYLE, style);
3954
3955 flush_events();
3956 flush_sequence();
3957 }
3958
3959 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3960 {
3961 struct recvd_message msg;
3962
3963 if (ignore_message( message )) return 0;
3964
3965 switch (message)
3966 {
3967 /* ignore */
3968 case WM_MOUSEMOVE:
3969 case WM_NCMOUSEMOVE:
3970 case WM_NCMOUSELEAVE:
3971 case WM_SETCURSOR:
3972 return 0;
3973 case WM_NCHITTEST:
3974 return HTCLIENT;
3975 }
3976
3977 msg.hwnd = hwnd;
3978 msg.message = message;
3979 msg.flags = sent|wparam|lparam;
3980 msg.wParam = wParam;
3981 msg.lParam = lParam;
3982 msg.descr = "dialog";
3983 add_message(&msg);
3984
3985 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3986 if (message == WM_TIMER) EndDialog( hwnd, 0 );
3987 return 0;
3988 }
3989
3990 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3991 {
3992 DWORD style, exstyle;
3993 INT xmin, xmax;
3994 BOOL ret;
3995
3996 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3997 style = GetWindowLongA(hwnd, GWL_STYLE);
3998 /* do not be confused by WS_DLGFRAME set */
3999 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4000
4001 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4002 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4003
4004 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4005 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4006 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4007 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4008 else
4009 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4010
4011 style = GetWindowLongA(hwnd, GWL_STYLE);
4012 if (set) ok(style & set, "style %08x should be set\n", set);
4013 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4014
4015 /* a subsequent call should do nothing */
4016 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4017 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4018 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4019
4020 xmin = 0xdeadbeef;
4021 xmax = 0xdeadbeef;
4022 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4023 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4024 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4025 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4026 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4027 }
4028
4029 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4030 {
4031 DWORD style, exstyle;
4032 SCROLLINFO si;
4033 BOOL ret;
4034
4035 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4036 style = GetWindowLongA(hwnd, GWL_STYLE);
4037 /* do not be confused by WS_DLGFRAME set */
4038 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4039
4040 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4041 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4042
4043 si.cbSize = sizeof(si);
4044 si.fMask = SIF_RANGE;
4045 si.nMin = min;
4046 si.nMax = max;
4047 SetScrollInfo(hwnd, ctl, &si, TRUE);
4048 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4049 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4050 else
4051 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4052
4053 style = GetWindowLongA(hwnd, GWL_STYLE);
4054 if (set) ok(style & set, "style %08x should be set\n", set);
4055 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4056
4057 /* a subsequent call should do nothing */
4058 SetScrollInfo(hwnd, ctl, &si, TRUE);
4059 if (style & WS_HSCROLL)
4060 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4061 else if (style & WS_VSCROLL)
4062 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4063 else
4064 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4065
4066 si.fMask = SIF_PAGE;
4067 si.nPage = 5;
4068 SetScrollInfo(hwnd, ctl, &si, FALSE);
4069 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4070
4071 si.fMask = SIF_POS;
4072 si.nPos = max - 1;
4073 SetScrollInfo(hwnd, ctl, &si, FALSE);
4074 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4075
4076 si.fMask = SIF_RANGE;
4077 si.nMin = 0xdeadbeef;
4078 si.nMax = 0xdeadbeef;
4079 ret = GetScrollInfo(hwnd, ctl, &si);
4080 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4081 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4082 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4083 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4084 }
4085
4086 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4087 static void test_scroll_messages(HWND hwnd)
4088 {
4089 SCROLLINFO si;
4090 INT min, max;
4091 BOOL ret;
4092
4093 flush_events();
4094 flush_sequence();
4095
4096 min = 0xdeadbeef;
4097 max = 0xdeadbeef;
4098 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4099 ok( ret, "GetScrollRange error %d\n", GetLastError());
4100 if (sequence->message != WmGetScrollRangeSeq[0].message)
4101 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4102 /* values of min and max are undefined */
4103 flush_sequence();
4104
4105 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4106 ok( ret, "SetScrollRange error %d\n", GetLastError());
4107 if (sequence->message != WmSetScrollRangeSeq[0].message)
4108 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4109 flush_sequence();
4110
4111 min = 0xdeadbeef;
4112 max = 0xdeadbeef;
4113 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4114 ok( ret, "GetScrollRange error %d\n", GetLastError());
4115 if (sequence->message != WmGetScrollRangeSeq[0].message)
4116 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4117 /* values of min and max are undefined */
4118 flush_sequence();
4119
4120 si.cbSize = sizeof(si);
4121 si.fMask = SIF_RANGE;
4122 si.nMin = 20;
4123 si.nMax = 160;
4124 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4125 if (sequence->message != WmSetScrollRangeSeq[0].message)
4126 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4127 flush_sequence();
4128
4129 si.fMask = SIF_PAGE;
4130 si.nPage = 10;
4131 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4132 if (sequence->message != WmSetScrollRangeSeq[0].message)
4133 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4134 flush_sequence();
4135
4136 si.fMask = SIF_POS;
4137 si.nPos = 20;
4138 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4139 if (sequence->message != WmSetScrollRangeSeq[0].message)
4140 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4141 flush_sequence();
4142
4143 si.fMask = SIF_RANGE;
4144 si.nMin = 0xdeadbeef;
4145 si.nMax = 0xdeadbeef;
4146 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4147 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4148 if (sequence->message != WmGetScrollInfoSeq[0].message)
4149 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4150 /* values of min and max are undefined */
4151 flush_sequence();
4152
4153 /* set WS_HSCROLL */
4154 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4155 /* clear WS_HSCROLL */
4156 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4157
4158 /* set WS_HSCROLL */
4159 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4160 /* clear WS_HSCROLL */
4161 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4162
4163 /* set WS_VSCROLL */
4164 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4165 /* clear WS_VSCROLL */
4166 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4167
4168 /* set WS_VSCROLL */
4169 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4170 /* clear WS_VSCROLL */
4171 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4172 }
4173
4174 static void test_showwindow(void)
4175 {
4176 HWND hwnd, hchild;
4177 RECT rc;
4178
4179 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4180 100, 100, 200, 200, 0, 0, 0, NULL);
4181 ok (hwnd != 0, "Failed to create overlapped window\n");
4182 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4183 0, 0, 10, 10, hwnd, 0, 0, NULL);
4184 ok (hchild != 0, "Failed to create child\n");
4185 flush_sequence();
4186
4187 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4188 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4189 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4190 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4191
4192 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4193 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4194 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4195 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4196 /* back to invisible */
4197 ShowWindow(hchild, SW_HIDE);
4198 ShowWindow(hwnd, SW_HIDE);
4199 flush_sequence();
4200 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4201 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4202 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4203 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4204 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4205 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4206 flush_sequence();
4207 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4208 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4209 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4210 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4211 ShowWindow( hwnd, SW_SHOW);
4212 flush_sequence();
4213 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4214 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4215 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4216
4217 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4218 ShowWindow( hchild, SW_HIDE);
4219 flush_sequence();
4220 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4221 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4222 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4223
4224 SetCapture(hchild);
4225 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4226 DestroyWindow(hchild);
4227 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4228
4229 DestroyWindow(hwnd);
4230 flush_sequence();
4231
4232 /* Popup windows */
4233 /* Test 1:
4234 * 1. Create invisible maximized popup window.
4235 * 2. Move and resize it.
4236 * 3. Show it maximized.
4237 */
4238 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4239 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4240 100, 100, 200, 200, 0, 0, 0, NULL);
4241 ok (hwnd != 0, "Failed to create popup window\n");
4242 ok(IsZoomed(hwnd), "window should be maximized\n");
4243 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4244
4245 GetWindowRect(hwnd, &rc);
4246 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4247 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4248 "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4249 rc.left, rc.top, rc.right, rc.bottom);
4250 /* Reset window's size & position */
4251 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4252 ok(IsZoomed(hwnd), "window should be maximized\n");
4253 flush_sequence();
4254
4255 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4256 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4257 ok(IsZoomed(hwnd), "window should be maximized\n");
4258 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4259
4260 GetWindowRect(hwnd, &rc);
4261 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4262 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4263 "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4264 rc.left, rc.top, rc.right, rc.bottom);
4265 DestroyWindow(hwnd);
4266 flush_sequence();
4267
4268 /* Test 2:
4269 * 1. Create invisible maximized popup window.
4270 * 2. Show it maximized.
4271 */
4272 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4273 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4274 100, 100, 200, 200, 0, 0, 0, NULL);
4275 ok (hwnd != 0, "Failed to create popup window\n");
4276 ok(IsZoomed(hwnd), "window should be maximized\n");
4277 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4278
4279 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4280 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4281 ok(IsZoomed(hwnd), "window should be maximized\n");
4282 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4283 DestroyWindow(hwnd);
4284 flush_sequence();
4285
4286 /* Test 3:
4287 * 1. Create visible maximized popup window.
4288 */
4289 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4290 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4291 100, 100, 200, 200, 0, 0, 0, NULL);
4292 ok (hwnd != 0, "Failed to create popup window\n");
4293 ok(IsZoomed(hwnd), "window should be maximized\n");
4294 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4295 DestroyWindow(hwnd);
4296 flush_sequence();
4297
4298 /* Test 4:
4299 * 1. Create visible popup window.
4300 * 2. Maximize it.
4301 */
4302 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4303 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4304 100, 100, 200, 200, 0, 0, 0, NULL);
4305 ok (hwnd != 0, "Failed to create popup window\n");
4306 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4307 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4308
4309 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4310 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4311 ok(IsZoomed(hwnd), "window should be maximized\n");
4312 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4313 DestroyWindow(hwnd);
4314 flush_sequence();
4315 }
4316
4317 static void test_sys_menu(void)
4318 {
4319 HWND hwnd;
4320 HMENU hmenu;
4321 UINT state;
4322
4323 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4324 100, 100, 200, 200, 0, 0, 0, NULL);
4325 ok (hwnd != 0, "Failed to create overlapped window\n");
4326
4327 flush_sequence();
4328
4329 /* test existing window without CS_NOCLOSE style */
4330 hmenu = GetSystemMenu(hwnd, FALSE);
4331 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4332
4333 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4334 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4335 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4336
4337 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4338 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4339
4340 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4341 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4342 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4343
4344 EnableMenuItem(hmenu, SC_CLOSE, 0);
4345 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4346
4347 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4348 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4349 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4350
4351 /* test whether removing WS_SYSMENU destroys a system menu */
4352 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4353 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4354 flush_sequence();
4355 hmenu = GetSystemMenu(hwnd, FALSE);
4356 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4357
4358 DestroyWindow(hwnd);
4359
4360 /* test new window with CS_NOCLOSE style */
4361 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4362 100, 100, 200, 200, 0, 0, 0, NULL);
4363 ok (hwnd != 0, "Failed to create overlapped window\n");
4364
4365 hmenu = GetSystemMenu(hwnd, FALSE);
4366 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4367
4368 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4369 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4370
4371 DestroyWindow(hwnd);
4372
4373 /* test new window without WS_SYSMENU style */
4374 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4375 100, 100, 200, 200, 0, 0, 0, NULL);
4376 ok(hwnd != 0, "Failed to create overlapped window\n");
4377
4378 hmenu = GetSystemMenu(hwnd, FALSE);
4379 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4380
4381 DestroyWindow(hwnd);
4382 }
4383
4384 /* For shown WS_OVERLAPPEDWINDOW */
4385 static const struct message WmSetIcon_1[] = {
4386 { WM_SETICON, sent },
4387 { 0x00AE, sent|defwinproc|optional }, /* XP */
4388 { WM_GETTEXT, sent|defwinproc|optional },
4389 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4390 { 0 }
4391 };
4392
4393 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4394 static const struct message WmSetIcon_2[] = {
4395 { WM_SETICON, sent },
4396 { 0 }
4397 };
4398
4399 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4400 static const struct message WmInitEndSession[] = {
4401 { 0x003B, sent },
4402 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4403 { 0 }
4404 };
4405
4406 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4407 static const struct message WmInitEndSession_2[] = {
4408 { 0x003B, sent },
4409 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4410 { 0 }
4411 };
4412
4413 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4414 static const struct message WmInitEndSession_3[] = {
4415 { 0x003B, sent },
4416 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4417 { 0 }
4418 };
4419
4420 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4421 static const struct message WmInitEndSession_4[] = {
4422 { 0x003B, sent },
4423 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4424 { 0 }
4425 };
4426
4427 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4428 static const struct message WmInitEndSession_5[] = {
4429 { 0x003B, sent },
4430 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4431 { 0 }
4432 };
4433
4434 static const struct message WmOptionalPaint[] = {
4435 { WM_PAINT, sent|optional },
4436 { WM_NCPAINT, sent|beginpaint|optional },
4437 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4438 { WM_ERASEBKGND, sent|beginpaint|optional },
4439 { 0 }
4440 };
4441
4442 static const struct message WmZOrder[] = {
4443 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4444 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4445 { HCBT_ACTIVATE, hook },
4446 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4447 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4448 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4449 { WM_GETTEXT, sent|optional },
4450 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4451 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4452 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4453 { WM_GETTEXT, sent|defwinproc|optional },
4454 { WM_GETTEXT, sent|defwinproc|optional },
4455 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4456 { HCBT_SETFOCUS, hook },
4457 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4458 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4459 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4460 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4461 { WM_GETTEXT, sent|optional },
4462 { WM_NCCALCSIZE, sent|optional },
4463 { 0 }
4464 };
4465
4466 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4467 {
4468 DWORD ret;
4469 MSG msg;
4470
4471 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4472 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4473
4474 PostMessageA(hwnd, WM_USER, 0, 0);
4475
4476 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4477 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4478
4479 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4480 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4481
4482 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4483 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4484
4485 PostMessageA(hwnd, WM_USER, 0, 0);
4486
4487 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4488 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4489
4490 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4491 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4492
4493 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4494 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4495 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4496
4497 PostMessageA(hwnd, WM_USER, 0, 0);
4498
4499 /* new incoming message causes it to become signaled again */
4500 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4501 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4502
4503 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4504 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4505 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4506 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4507 }
4508
4509 /* test if we receive the right sequence of messages */
4510 static void test_messages(void)
4511 {
4512 HWND hwnd, hparent, hchild;
4513 HWND hchild2, hbutton;
4514 HMENU hmenu;
4515 MSG msg;
4516 LRESULT res;
4517
4518 flush_sequence();
4519
4520 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4521 100, 100, 200, 200, 0, 0, 0, NULL);
4522 ok (hwnd != 0, "Failed to create overlapped window\n");
4523 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4524
4525 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4526 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4527 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4528
4529 /* test WM_SETREDRAW on a not visible top level window */
4530 test_WM_SETREDRAW(hwnd);
4531
4532 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4533 flush_events();
4534 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4535 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4536
4537 ok(GetActiveWindow() == hwnd, "window should be active\n");
4538 ok(GetFocus() == hwnd, "window should have input focus\n");
4539 ShowWindow(hwnd, SW_HIDE);
4540 flush_events();
4541 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4542
4543 ShowWindow(hwnd, SW_SHOW);
4544 flush_events();
4545 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4546
4547 ShowWindow(hwnd, SW_HIDE);
4548 flush_events();
4549 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4550
4551 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4552 flush_events();
4553 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4554 flush_sequence();
4555
4556 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4557 {
4558 ShowWindow(hwnd, SW_RESTORE);
4559 flush_events();
4560 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4561 flush_sequence();
4562 }
4563
4564 ShowWindow(hwnd, SW_MINIMIZE);
4565 flush_events();
4566 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4567 flush_sequence();
4568
4569 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4570 {
4571 ShowWindow(hwnd, SW_RESTORE);
4572 flush_events();
4573 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4574 flush_sequence();
4575 }
4576
4577 ShowWindow(hwnd, SW_SHOW);
4578 flush_events();
4579 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4580
4581 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4582 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4583 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4584 ok(GetActiveWindow() == hwnd, "window should still be active\n");
4585
4586 /* test WM_SETREDRAW on a visible top level window */
4587 ShowWindow(hwnd, SW_SHOW);
4588 flush_events();
4589 test_WM_SETREDRAW(hwnd);
4590
4591 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4592 test_scroll_messages(hwnd);
4593
4594 /* test resizing and moving */
4595 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4596 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4597 flush_events();
4598 flush_sequence();
4599 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4600 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4601 flush_events();
4602 flush_sequence();
4603 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4604 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4605 flush_events();
4606 flush_sequence();
4607
4608 /* popups don't get WM_GETMINMAXINFO */
4609 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4610 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4611 flush_sequence();
4612 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4613 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4614
4615 DestroyWindow(hwnd);
4616 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4617
4618 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4619 100, 100, 200, 200, 0, 0, 0, NULL);
4620 ok (hparent != 0, "Failed to create parent window\n");
4621 flush_sequence();
4622
4623 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4624 0, 0, 10, 10, hparent, 0, 0, NULL);
4625 ok (hchild != 0, "Failed to create child window\n");
4626 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4627 DestroyWindow(hchild);
4628 flush_sequence();
4629
4630 /* visible child window with a caption */
4631 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4632 WS_CHILD | WS_VISIBLE | WS_CAPTION,
4633 0, 0, 10, 10, hparent, 0, 0, NULL);
4634 ok (hchild != 0, "Failed to create child window\n");
4635 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4636
4637 trace("testing scroll APIs on a visible child window %p\n", hchild);
4638 test_scroll_messages(hchild);
4639
4640 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4641 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4642
4643 DestroyWindow(hchild);
4644 flush_sequence();
4645
4646 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4647 0, 0, 10, 10, hparent, 0, 0, NULL);
4648 ok (hchild != 0, "Failed to create child window\n");
4649 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4650
4651 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4652 100, 100, 50, 50, hparent, 0, 0, NULL);
4653 ok (hchild2 != 0, "Failed to create child2 window\n");
4654 flush_sequence();
4655
4656 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4657 0, 100, 50, 50, hchild, 0, 0, NULL);
4658 ok (hbutton != 0, "Failed to create button window\n");
4659
4660 /* test WM_SETREDRAW on a not visible child window */
4661 test_WM_SETREDRAW(hchild);
4662
4663 ShowWindow(hchild, SW_SHOW);
4664 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4665
4666 /* check parent messages too */
4667 log_all_parent_messages++;
4668 ShowWindow(hchild, SW_HIDE);
4669 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4670 log_all_parent_messages--;
4671
4672 ShowWindow(hchild, SW_SHOW);
4673 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4674
4675 ShowWindow(hchild, SW_HIDE);
4676 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4677
4678 ShowWindow(hchild, SW_SHOW);
4679 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4680
4681 /* test WM_SETREDRAW on a visible child window */
4682 test_WM_SETREDRAW(hchild);
4683
4684 log_all_parent_messages++;
4685 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4686 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4687 log_all_parent_messages--;
4688
4689 ShowWindow(hchild, SW_HIDE);
4690 flush_sequence();
4691 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4692 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4693
4694 ShowWindow(hchild, SW_HIDE);
4695 flush_sequence();
4696 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4697 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4698
4699 /* DestroyWindow sequence below expects that a child has focus */
4700 SetFocus(hchild);
4701 flush_sequence();
4702
4703 DestroyWindow(hchild);
4704 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4705 DestroyWindow(hchild2);
4706 DestroyWindow(hbutton);
4707
4708 flush_sequence();
4709 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4710 0, 0, 100, 100, hparent, 0, 0, NULL);
4711 ok (hchild != 0, "Failed to create child popup window\n");
4712 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4713 DestroyWindow(hchild);
4714
4715 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4716 flush_sequence();
4717 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4718 0, 0, 100, 100, hparent, 0, 0, NULL);
4719 ok (hchild != 0, "Failed to create popup window\n");
4720 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4721 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4722 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4723 flush_sequence();
4724 ShowWindow(hchild, SW_SHOW);
4725 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4726 flush_sequence();
4727 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4728 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4729 flush_sequence();
4730 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4731 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4732 DestroyWindow(hchild);
4733
4734 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4735 * changes nothing in message sequences.
4736 */
4737 flush_sequence();
4738 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4739 0, 0, 100, 100, hparent, 0, 0, NULL);
4740 ok (hchild != 0, "Failed to create popup window\n");
4741 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4742 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4743 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4744 flush_sequence();
4745 ShowWindow(hchild, SW_SHOW);
4746 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4747 flush_sequence();
4748 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4749 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4750 DestroyWindow(hchild);
4751
4752 flush_sequence();
4753 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4754 0, 0, 100, 100, hparent, 0, 0, NULL);
4755 ok(hwnd != 0, "Failed to create custom dialog window\n");
4756 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4757
4758 if(0) {
4759 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4760 test_scroll_messages(hwnd);
4761 }
4762
4763 flush_sequence();
4764
4765 test_def_id = 1;
4766 SendMessageA(hwnd, WM_NULL, 0, 0);
4767
4768 flush_sequence();
4769 after_end_dialog = 1;
4770 EndDialog( hwnd, 0 );
4771 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4772
4773 DestroyWindow(hwnd);
4774 after_end_dialog = 0;
4775 test_def_id = 0;
4776
4777 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4778 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4779 ok(hwnd != 0, "Failed to create custom dialog window\n");
4780 flush_sequence();
4781 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4782 ShowWindow(hwnd, SW_SHOW);
4783 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4784 DestroyWindow(hwnd);
4785
4786 flush_sequence();
4787 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4788 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4789
4790 DestroyWindow(hparent);
4791 flush_sequence();
4792
4793 /* Message sequence for SetMenu */
4794 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4795 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4796
4797 hmenu = CreateMenu();
4798 ok (hmenu != 0, "Failed to create menu\n");
4799 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4800 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4801 100, 100, 200, 200, 0, hmenu, 0, NULL);
4802 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4803 ok (SetMenu(hwnd, 0), "SetMenu\n");
4804 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4805 ok (SetMenu(hwnd, 0), "SetMenu\n");
4806 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4807 ShowWindow(hwnd, SW_SHOW);
4808 UpdateWindow( hwnd );
4809 flush_events();
4810 flush_sequence();
4811 ok (SetMenu(hwnd, 0), "SetMenu\n");
4812 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4813 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4814 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4815
4816 UpdateWindow( hwnd );
4817 flush_events();
4818 flush_sequence();
4819 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4820 flush_events();
4821 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4822
4823 DestroyWindow(hwnd);
4824 flush_sequence();
4825
4826 /* Message sequence for EnableWindow */
4827 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4828 100, 100, 200, 200, 0, 0, 0, NULL);
4829 ok (hparent != 0, "Failed to create parent window\n");
4830 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4831 0, 0, 10, 10, hparent, 0, 0, NULL);
4832 ok (hchild != 0, "Failed to create child window\n");
4833
4834 SetFocus(hchild);
4835 flush_events();
4836 flush_sequence();
4837
4838 EnableWindow(hparent, FALSE);
4839 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4840
4841 EnableWindow(hparent, TRUE);
4842 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4843
4844 flush_events();
4845 flush_sequence();
4846
4847 test_MsgWaitForMultipleObjects(hparent);
4848
4849 /* the following test causes an exception in user.exe under win9x */
4850 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4851 {
4852 DestroyWindow(hparent);
4853 flush_sequence();
4854 return;
4855 }
4856 PostMessageW( hparent, WM_USER+1, 0, 0 );
4857 /* PeekMessage(NULL) fails, but still removes the message */
4858 SetLastError(0xdeadbeef);
4859 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4860 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4861 GetLastError() == 0xdeadbeef, /* NT4 */
4862 "last error is %d\n", GetLastError() );
4863 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4864 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4865
4866 DestroyWindow(hchild);
4867 DestroyWindow(hparent);
4868 flush_sequence();
4869
4870 /* Message sequences for WM_SETICON */
4871 trace("testing WM_SETICON\n");
4872 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4873 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4874 NULL, NULL, 0);
4875 ShowWindow(hwnd, SW_SHOW);
4876 UpdateWindow(hwnd);
4877 flush_events();
4878 flush_sequence();
4879 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4880 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4881
4882 ShowWindow(hwnd, SW_HIDE);
4883 flush_events();
4884 flush_sequence();
4885 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4886 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4887 DestroyWindow(hwnd);
4888 flush_sequence();
4889
4890 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4891 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4892 NULL, NULL, 0);
4893 ShowWindow(hwnd, SW_SHOW);
4894 UpdateWindow(hwnd);
4895 flush_events();
4896 flush_sequence();
4897 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4898 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4899
4900 ShowWindow(hwnd, SW_HIDE);
4901 flush_events();
4902 flush_sequence();
4903 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
4904 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4905
4906 flush_sequence();
4907 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
4908 if (!res)
4909 {
4910 todo_wine win_skip( "Message 0x3b not supported\n" );
4911 goto done;
4912 }
4913 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4914 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4915 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
4916 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4917 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4918 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
4919 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4920 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4921
4922 flush_sequence();
4923 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
4924 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4925 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4926 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
4927 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4928 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4929
4930 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
4931 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4932 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4933
4934 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
4935 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4936 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4937
4938 done:
4939 DestroyWindow(hwnd);
4940 flush_sequence();
4941 }
4942
4943 static void test_setwindowpos(void)
4944 {
4945 HWND hwnd;
4946 RECT rc;
4947 LRESULT res;
4948 const INT winX = 100;
4949 const INT winY = 100;
4950 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4951
4952 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4953 0, 0, winX, winY, 0,
4954 NULL, NULL, 0);
4955
4956 GetWindowRect(hwnd, &rc);
4957 expect(sysX, rc.right);
4958 expect(winY, rc.bottom);
4959
4960 flush_events();
4961 flush_sequence();
4962 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4963 ok_sequence(WmZOrder, "Z-Order", TRUE);
4964 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4965
4966 GetWindowRect(hwnd, &rc);
4967 expect(sysX, rc.right);
4968 expect(winY, rc.bottom);
4969 DestroyWindow(hwnd);
4970 }
4971
4972 static void invisible_parent_tests(void)
4973 {
4974 HWND hparent, hchild;
4975
4976 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4977 100, 100, 200, 200, 0, 0, 0, NULL);
4978 ok (hparent != 0, "Failed to create parent window\n");
4979 flush_sequence();
4980
4981 /* test showing child with hidden parent */
4982
4983 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4984 0, 0, 10, 10, hparent, 0, 0, NULL);
4985 ok (hchild != 0, "Failed to create child window\n");
4986 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4987
4988 ShowWindow( hchild, SW_MINIMIZE );
4989 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4990 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4991 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4992
4993 /* repeat */
4994 flush_events();
4995 flush_sequence();
4996 ShowWindow( hchild, SW_MINIMIZE );
4997 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4998
4999 DestroyWindow(hchild);
5000 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5001 0, 0, 10, 10, hparent, 0, 0, NULL);
5002 flush_sequence();
5003
5004 ShowWindow( hchild, SW_MAXIMIZE );
5005 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5006 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5007 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5008
5009 /* repeat */
5010 flush_events();
5011 flush_sequence();
5012 ShowWindow( hchild, SW_MAXIMIZE );
5013 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5014
5015 DestroyWindow(hchild);
5016 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5017 0, 0, 10, 10, hparent, 0, 0, NULL);
5018 flush_sequence();
5019
5020 ShowWindow( hchild, SW_RESTORE );
5021 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5022 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5023 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5024
5025 DestroyWindow(hchild);
5026 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5027 0, 0, 10, 10, hparent, 0, 0, NULL);
5028 flush_sequence();
5029
5030 ShowWindow( hchild, SW_SHOWMINIMIZED );
5031 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5032 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5033 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5034
5035 /* repeat */
5036 flush_events();
5037 flush_sequence();
5038 ShowWindow( hchild, SW_SHOWMINIMIZED );
5039 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5040
5041 DestroyWindow(hchild);
5042 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5043 0, 0, 10, 10, hparent, 0, 0, NULL);
5044 flush_sequence();
5045
5046 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5047 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5048 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5049 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5050 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5051
5052 DestroyWindow(hchild);
5053 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5054 0, 0, 10, 10, hparent, 0, 0, NULL);
5055 flush_sequence();
5056
5057 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5058 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5059 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5060 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5061
5062 /* repeat */
5063 flush_events();
5064 flush_sequence();
5065 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5066 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5067
5068 DestroyWindow(hchild);
5069 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5070 0, 0, 10, 10, hparent, 0, 0, NULL);
5071 flush_sequence();
5072
5073 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5074 ShowWindow( hchild, SW_FORCEMINIMIZE );
5075 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5076 todo_wine {
5077 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5078 }
5079 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5080
5081 DestroyWindow(hchild);
5082 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5083 0, 0, 10, 10, hparent, 0, 0, NULL);
5084 flush_sequence();
5085
5086 ShowWindow( hchild, SW_SHOWNA );
5087 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5088 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5089 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5090
5091 /* repeat */
5092 flush_events();
5093 flush_sequence();
5094 ShowWindow( hchild, SW_SHOWNA );
5095 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5096
5097 DestroyWindow(hchild);
5098 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5099 0, 0, 10, 10, hparent, 0, 0, NULL);
5100 flush_sequence();
5101
5102 ShowWindow( hchild, SW_SHOW );
5103 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5104 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5105 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5106
5107 /* repeat */
5108 flush_events();
5109 flush_sequence();
5110 ShowWindow( hchild, SW_SHOW );
5111 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5112
5113 ShowWindow( hchild, SW_HIDE );
5114 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5115 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5116 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5117
5118 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5119 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5120 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5121 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5122
5123 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5124 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5125 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5126 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5127
5128 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5129 flush_sequence();
5130 DestroyWindow(hchild);
5131 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5132
5133 DestroyWindow(hparent);
5134 flush_sequence();
5135 }
5136
5137 /****************** button message test *************************/
5138 #define ID_BUTTON 0x000e
5139
5140 static const struct message WmSetFocusButtonSeq[] =
5141 {
5142 { HCBT_SETFOCUS, hook },
5143 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5144 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5145 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5146 { WM_SETFOCUS, sent|wparam, 0 },
5147 { WM_CTLCOLORBTN, sent|parent },
5148 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5149 { WM_APP, sent|wparam|lparam, 0, 0 },
5150 { 0 }
5151 };
5152 static const struct message WmKillFocusButtonSeq[] =
5153 {
5154 { HCBT_SETFOCUS, hook },
5155 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5156 { WM_KILLFOCUS, sent|wparam, 0 },
5157 { WM_CTLCOLORBTN, sent|parent },
5158 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5159 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5160 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5161 { WM_APP, sent|wparam|lparam, 0, 0 },
5162 { WM_PAINT, sent },
5163 { WM_CTLCOLORBTN, sent|parent },
5164 { 0 }
5165 };
5166 static const struct message WmSetFocusStaticSeq[] =
5167 {
5168 { HCBT_SETFOCUS, hook },
5169 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5170 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5171 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5172 { WM_SETFOCUS, sent|wparam, 0 },
5173 { WM_CTLCOLORSTATIC, sent|parent },
5174 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5175 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5176 { WM_APP, sent|wparam|lparam, 0, 0 },
5177 { 0 }
5178 };
5179 static const struct message WmKillFocusStaticSeq[] =
5180 {
5181 { HCBT_SETFOCUS, hook },
5182 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5183 { WM_KILLFOCUS, sent|wparam, 0 },
5184 { WM_CTLCOLORSTATIC, sent|parent },
5185 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5186 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5187 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5188 { WM_APP, sent|wparam|lparam, 0, 0 },
5189 { WM_PAINT, sent },
5190 { WM_CTLCOLORSTATIC, sent|parent },
5191 { 0 }
5192 };
5193 static const struct message WmSetFocusOwnerdrawSeq[] =
5194 {
5195 { HCBT_SETFOCUS, hook },
5196 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5197 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5198 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5199 { WM_SETFOCUS, sent|wparam, 0 },
5200 { WM_CTLCOLORBTN, sent|parent },
5201 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5202 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5203 { WM_APP, sent|wparam|lparam, 0, 0 },
5204 { 0 }
5205 };
5206 static const struct message WmKillFocusOwnerdrawSeq[] =
5207 {
5208 { HCBT_SETFOCUS, hook },
5209 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5210 { WM_KILLFOCUS, sent|wparam, 0 },
5211 { WM_CTLCOLORBTN, sent|parent },
5212 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5213 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5214 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5215 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5216 { WM_APP, sent|wparam|lparam, 0, 0 },
5217 { WM_PAINT, sent },
5218 { WM_CTLCOLORBTN, sent|parent },
5219 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5220 { 0 }
5221 };
5222 static const struct message WmLButtonDownSeq[] =
5223 {
5224 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5225 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5226 { HCBT_SETFOCUS, hook },
5227 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5228 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5229 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5230 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5231 { WM_CTLCOLORBTN, sent|defwinproc },
5232 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5233 { WM_CTLCOLORBTN, sent|defwinproc },
5234 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5235 { 0 }
5236 };
5237 static const struct message WmLButtonUpSeq[] =
5238 {
5239 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5240 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5241 { WM_CTLCOLORBTN, sent|defwinproc },
5242 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5243 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5244 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5245 { 0 }
5246 };
5247 static const struct message WmSetFontButtonSeq[] =
5248 {
5249 { WM_SETFONT, sent },
5250 { WM_PAINT, sent },
5251 { WM_ERASEBKGND, sent|defwinproc|optional },
5252 { WM_CTLCOLORBTN, sent|defwinproc },
5253 { 0 }
5254 };
5255 static const struct message WmSetStyleButtonSeq[] =
5256 {
5257 { BM_SETSTYLE, sent },
5258 { WM_APP, sent|wparam|lparam, 0, 0 },
5259 { WM_PAINT, sent },
5260 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5261 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5262 { WM_CTLCOLORBTN, sent|parent },
5263 { 0 }
5264 };
5265 static const struct message WmSetStyleStaticSeq[] =
5266 {
5267 { BM_SETSTYLE, sent },
5268 { WM_APP, sent|wparam|lparam, 0, 0 },
5269 { WM_PAINT, sent },
5270 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5271 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5272 { WM_CTLCOLORSTATIC, sent|parent },
5273 { 0 }
5274 };
5275 static const struct message WmSetStyleUserSeq[] =
5276 {
5277 { BM_SETSTYLE, sent },
5278 { WM_APP, sent|wparam|lparam, 0, 0 },
5279 { WM_PAINT, sent },
5280 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5281 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5282 { WM_CTLCOLORBTN, sent|parent },
5283 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5284 { 0 }
5285 };
5286 static const struct message WmSetStyleOwnerdrawSeq[] =
5287 {
5288 { BM_SETSTYLE, sent },
5289 { WM_APP, sent|wparam|lparam, 0, 0 },
5290 { WM_PAINT, sent },
5291 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5292 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5293 { WM_CTLCOLORBTN, sent|parent },
5294 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5295 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5296 { 0 }
5297 };
5298 static const struct message WmSetStateButtonSeq[] =
5299 {
5300 { BM_SETSTATE, sent },
5301 { WM_CTLCOLORBTN, sent|parent },
5302 { WM_APP, sent|wparam|lparam, 0, 0 },
5303 { 0 }
5304 };
5305 static const struct message WmSetStateStaticSeq[] =
5306 {
5307 { BM_SETSTATE, sent },
5308 { WM_CTLCOLORSTATIC, sent|parent },
5309 { WM_APP, sent|wparam|lparam, 0, 0 },
5310 { 0 }
5311 };
5312 static const struct message WmSetStateUserSeq[] =
5313 {
5314 { BM_SETSTATE, sent },
5315 { WM_CTLCOLORBTN, sent|parent },
5316 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
5317 { WM_APP, sent|wparam|lparam, 0, 0 },
5318 { 0 }
5319 };
5320 static const struct message WmSetStateOwnerdrawSeq[] =
5321 {
5322 { BM_SETSTATE, sent },
5323 { WM_CTLCOLORBTN, sent|parent },
5324 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
5325 { WM_APP, sent|wparam|lparam, 0, 0 },
5326 { 0 }
5327 };
5328 static const struct message WmClearStateButtonSeq[] =
5329 {
5330 { BM_SETSTATE, sent },
5331 { WM_CTLCOLORBTN, sent|parent },
5332 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
5333 { WM_APP, sent|wparam|lparam, 0, 0 },
5334 { 0 }
5335 };
5336 static const struct message WmClearStateOwnerdrawSeq[] =
5337 {
5338 { BM_SETSTATE, sent },
5339 { WM_CTLCOLORBTN, sent|parent },
5340 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
5341 { WM_APP, sent|wparam|lparam, 0, 0 },
5342 { 0 }
5343 };
5344 static const struct message WmSetCheckIgnoredSeq[] =
5345 {
5346 { BM_SETCHECK, sent },
5347 { WM_APP, sent|wparam|lparam, 0, 0 },
5348 { 0 }
5349 };
5350 static const struct message WmSetCheckStaticSeq[] =
5351 {
5352 { BM_SETCHECK, sent },
5353 { WM_CTLCOLORSTATIC, sent|parent },
5354 { WM_APP, sent|wparam|lparam, 0, 0 },
5355 { 0 }
5356 };
5357
5358 static WNDPROC old_button_proc;
5359
5360 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5361 {
5362 static LONG defwndproc_counter = 0;
5363 LRESULT ret;
5364 struct recvd_message msg;
5365
5366 if (ignore_message( message )) return 0;
5367
5368 switch (message)
5369 {
5370 case WM_SYNCPAINT:
5371 break;
5372 case BM_SETSTATE:
5373 if (GetCapture())
5374 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5375 /* fall through */
5376 default:
5377 msg.hwnd = hwnd;
5378 msg.message = message;
5379 msg.flags = sent|wparam|lparam;
5380 if (defwndproc_counter) msg.flags |= defwinproc;
5381 msg.wParam = wParam;
5382 msg.lParam = lParam;
5383 msg.descr = "button";
5384 add_message(&msg);
5385 }
5386
5387 defwndproc_counter++;
5388 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5389 defwndproc_counter--;
5390
5391 return ret;
5392 }
5393
5394 static void subclass_button(void)
5395 {
5396 WNDCLASSA cls;
5397
5398 if (!GetClassInfoA(0, "button", &cls)) assert(0);
5399
5400 old_button_proc = cls.lpfnWndProc;
5401
5402 cls.hInstance = GetModuleHandleA(NULL);
5403 cls.lpfnWndProc = button_hook_proc;
5404 cls.lpszClassName = "my_button_class";
5405 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5406 if (!RegisterClassA(&cls)) assert(0);
5407 }
5408
5409 static void test_button_messages(void)
5410 {
5411 static const struct
5412 {
5413 DWORD style;
5414 DWORD dlg_code;
5415 const struct message *setfocus;
5416 const struct message *killfocus;
5417 const struct message *setstyle;
5418 const struct message *setstate;
5419 const struct message *clearstate;
5420 const struct message *setcheck;
5421 } button[] = {
5422 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5423 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5424 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5425 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5426 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5427 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5428 { BS_CHECKBOX, DLGC_BUTTON,
5429 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5430 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5431 { BS_AUTOCHECKBOX, DLGC_BUTTON,
5432 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5433 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5434 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5435 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5436 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5437 { BS_3STATE, DLGC_BUTTON,
5438 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5439 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5440 { BS_AUTO3STATE, DLGC_BUTTON,
5441 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5442 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5443 { BS_GROUPBOX, DLGC_STATIC,
5444 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5445 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
5446 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5447 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
5448 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
5449 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5450 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5451 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5452 { BS_OWNERDRAW, DLGC_BUTTON,
5453 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
5454 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
5455 };
5456 unsigned int i;
5457 HWND hwnd, parent;
5458 DWORD dlg_code;
5459 HFONT zfont;
5460
5461 /* selection with VK_SPACE should capture button window */
5462 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5463 0, 0, 50, 14, 0, 0, 0, NULL);
5464 ok(hwnd != 0, "Failed to create button window\n");
5465 ReleaseCapture();
5466 SetFocus(hwnd);
5467 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5468 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5469 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5470 DestroyWindow(hwnd);
5471
5472 subclass_button();
5473
5474 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5475 100, 100, 200, 200, 0, 0, 0, NULL);
5476 ok(parent != 0, "Failed to create parent window\n");
5477
5478 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5479 {
5480 MSG msg;
5481 DWORD style, state;
5482
5483 trace("button style %08x\n", button[i].style);
5484
5485 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5486 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5487 ok(hwnd != 0, "Failed to create button window\n");
5488
5489 style = GetWindowLongA(hwnd, GWL_STYLE);
5490 style &= ~(WS_CHILD | BS_NOTIFY);
5491 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5492 if (button[i].style == BS_USERBUTTON)
5493 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5494 else
5495 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5496
5497 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5498 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5499
5500 ShowWindow(hwnd, SW_SHOW);
5501 UpdateWindow(hwnd);
5502 SetFocus(0);
5503 flush_events();
5504 SetFocus(0);
5505 flush_sequence();
5506
5507 log_all_parent_messages++;
5508
5509 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5510 SetFocus(hwnd);
5511 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5512 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5513 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5514
5515 SetFocus(0);
5516 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5517 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5518 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5519
5520 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5521
5522 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5523 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5524 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5525 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5526
5527 style = GetWindowLongA(hwnd, GWL_STYLE);
5528 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5529 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5530 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5531
5532 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5533 ok(state == 0, "expected state 0, got %04x\n", state);
5534
5535 flush_sequence();
5536
5537 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
5538 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5539 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5540 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
5541
5542 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5543 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
5544
5545 style = GetWindowLongA(hwnd, GWL_STYLE);
5546 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5547 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5548
5549 flush_sequence();
5550
5551 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
5552 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5553 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5554 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
5555
5556 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
5557 ok(state == 0, "expected state 0, got %04x\n", state);
5558
5559 style = GetWindowLongA(hwnd, GWL_STYLE);
5560 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5561 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5562
5563 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5564 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5565
5566 flush_sequence();
5567
5568 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
5569 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5570 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5571 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
5572
5573 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5574 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5575
5576 style = GetWindowLongA(hwnd, GWL_STYLE);
5577 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5578 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5579
5580 flush_sequence();
5581
5582 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
5583 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5584 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
5585 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
5586
5587 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
5588 if (button[i].style == BS_PUSHBUTTON ||
5589 button[i].style == BS_DEFPUSHBUTTON ||
5590 button[i].style == BS_GROUPBOX ||
5591 button[i].style == BS_USERBUTTON ||
5592 button[i].style == BS_OWNERDRAW)
5593 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
5594 else
5595 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
5596
5597 style = GetWindowLongA(hwnd, GWL_STYLE);
5598 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5599 if (button[i].style == BS_RADIOBUTTON ||
5600 button[i].style == BS_AUTORADIOBUTTON)
5601 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
5602 else
5603 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5604
5605 log_all_parent_messages--;
5606
5607 DestroyWindow(hwnd);
5608 }
5609
5610 DestroyWindow(parent);
5611
5612 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5613 0, 0, 50, 14, 0, 0, 0, NULL);
5614 ok(hwnd != 0, "Failed to create button window\n");
5615
5616 SetForegroundWindow(hwnd);
5617 flush_events();
5618
5619 SetActiveWindow(hwnd);
5620 SetFocus(0);
5621 flush_sequence();
5622
5623 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5624 ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5625
5626 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5627 ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5628
5629 flush_sequence();
5630 zfont = GetStockObject(SYSTEM_FONT);
5631 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5632 UpdateWindow(hwnd);
5633 ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5634
5635 DestroyWindow(hwnd);
5636 }
5637
5638 /****************** static message test *************************/
5639 static const struct message WmSetFontStaticSeq[] =
5640 {
5641 { WM_SETFONT, sent },
5642 { WM_PAINT, sent|defwinproc|optional },
5643 { WM_ERASEBKGND, sent|defwinproc|optional },
5644 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5645 { 0 }
5646 };
5647
5648 static WNDPROC old_static_proc;
5649
5650 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5651 {
5652 static LONG defwndproc_counter = 0;
5653 LRESULT ret;
5654 struct recvd_message msg;
5655
5656 if (ignore_message( message )) return 0;
5657
5658 msg.hwnd = hwnd;
5659 msg.message = message;
5660 msg.flags = sent|wparam|lparam;
5661 if (defwndproc_counter) msg.flags |= defwinproc;
5662 msg.wParam = wParam;
5663 msg.lParam = lParam;
5664 msg.descr = "static";
5665 add_message(&msg);
5666
5667 defwndproc_counter++;
5668 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5669 defwndproc_counter--;
5670
5671 return ret;
5672 }
5673
5674 static void subclass_static(void)
5675 {
5676 WNDCLASSA cls;
5677
5678 if (!GetClassInfoA(0, "static", &cls)) assert(0);
5679
5680 old_static_proc = cls.lpfnWndProc;
5681
5682 cls.hInstance = GetModuleHandleA(NULL);
5683 cls.lpfnWndProc = static_hook_proc;
5684 cls.lpszClassName = "my_static_class";
5685 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5686 if (!RegisterClassA(&cls)) assert(0);
5687 }
5688
5689 static void test_static_messages(void)
5690 {
5691 /* FIXME: make as comprehensive as the button message test */
5692 static const struct
5693 {
5694 DWORD style;
5695 DWORD dlg_code;
5696 const struct message *setfont;
5697 } static_ctrl[] = {
5698 { SS_LEFT, DLGC_STATIC,
5699 WmSetFontStaticSeq }
5700 };
5701 unsigned int i;
5702 HWND hwnd;
5703 DWORD dlg_code;
5704
5705 subclass_static();
5706
5707 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5708 {
5709 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5710 0, 0, 50, 14, 0, 0, 0, NULL);
5711 ok(hwnd != 0, "Failed to create static window\n");
5712
5713 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5714 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5715
5716 ShowWindow(hwnd, SW_SHOW);
5717 UpdateWindow(hwnd);
5718 SetFocus(0);
5719 flush_sequence();
5720
5721 trace("static style %08x\n", static_ctrl[i].style);
5722 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5723 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5724
5725 DestroyWindow(hwnd);
5726 }
5727 }
5728
5729 /****************** ComboBox message test *************************/
5730 #define ID_COMBOBOX 0x000f
5731
5732 static const struct message WmKeyDownComboSeq[] =
5733 {
5734 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5735 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5736 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5737 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5738 { WM_CTLCOLOREDIT, sent|parent },
5739 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5740 { 0 }
5741 };
5742
5743 static const struct message WmSetPosComboSeq[] =
5744 {
5745 { WM_WINDOWPOSCHANGING, sent },
5746 { WM_NCCALCSIZE, sent|wparam, TRUE },
5747 { WM_CHILDACTIVATE, sent },
5748 { WM_WINDOWPOSCHANGED, sent },
5749 { WM_MOVE, sent|defwinproc },
5750 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5751 { WM_WINDOWPOSCHANGING, sent|defwinproc },
5752 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
5753 { WM_WINDOWPOSCHANGED, sent|defwinproc },
5754 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5755 { 0 }
5756 };
5757
5758 static WNDPROC old_combobox_proc;
5759
5760 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5761 {
5762 static LONG defwndproc_counter = 0;
5763 LRESULT ret;
5764 struct recvd_message msg;
5765
5766 /* do not log painting messages */
5767 if (message != WM_PAINT &&
5768 message != WM_NCPAINT &&
5769 message != WM_SYNCPAINT &&
5770 message != WM_ERASEBKGND &&
5771 message != WM_NCHITTEST &&
5772 message != WM_GETTEXT &&
5773 !ignore_message( message ))
5774 {
5775 msg.hwnd = hwnd;
5776 msg.message = message;
5777 msg.flags = sent|wparam|lparam;
5778 if (defwndproc_counter) msg.flags |= defwinproc;
5779 msg.wParam = wParam;
5780 msg.lParam = lParam;
5781 msg.descr = "combo";
5782 add_message(&msg);
5783 }
5784
5785 defwndproc_counter++;
5786 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5787 defwndproc_counter--;
5788
5789 return ret;
5790 }
5791
5792 static void subclass_combobox(void)
5793 {
5794 WNDCLASSA cls;
5795
5796 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5797
5798 old_combobox_proc = cls.lpfnWndProc;
5799
5800 cls.hInstance = GetModuleHandleA(NULL);
5801 cls.lpfnWndProc = combobox_hook_proc;
5802 cls.lpszClassName = "my_combobox_class";
5803 UnregisterClassA(cls.lpszClassName, cls.hInstance);
5804 if (!RegisterClassA(&cls)) assert(0);
5805 }
5806
5807 static void test_combobox_messages(void)
5808 {
5809 HWND parent, combo;
5810 LRESULT ret;
5811
5812 subclass_combobox();
5813
5814 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5815 100, 100, 200, 200, 0, 0, 0, NULL);
5816 ok(parent != 0, "Failed to create parent window\n");
5817 flush_sequence();
5818
5819 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5820 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5821 ok(combo != 0, "Failed to create combobox window\n");
5822
5823 UpdateWindow(combo);
5824
5825 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
5826 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5827
5828 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5829 ok(ret == 0, "expected 0, got %ld\n", ret);
5830 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5831 ok(ret == 1, "expected 1, got %ld\n", ret);
5832 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5833 ok(ret == 2, "expected 2, got %ld\n", ret);
5834
5835 SendMessageA(combo, CB_SETCURSEL, 0, 0);
5836 SetFocus(combo);
5837 flush_sequence();
5838
5839 log_all_parent_messages++;
5840 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
5841 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
5842 log_all_parent_messages--;
5843 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5844
5845 flush_sequence();
5846 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
5847 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
5848
5849 DestroyWindow(combo);
5850 DestroyWindow(parent);
5851 }
5852
5853 /****************** WM_IME_KEYDOWN message test *******************/
5854
5855 static const struct message WmImeKeydownMsgSeq_0[] =
5856 {
5857 { WM_IME_KEYDOWN, wparam, VK_RETURN },
5858 { WM_CHAR, wparam, 'A' },
5859 { 0 }
5860 };
5861
5862 static const struct message WmImeKeydownMsgSeq_1[] =
5863 {
5864 { WM_KEYDOWN, optional|wparam, VK_RETURN },
5865 { WM_CHAR, optional|wparam, VK_RETURN },
5866 { 0 }
5867 };
5868
5869 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5870 {
5871 struct recvd_message msg;
5872
5873 msg.hwnd = hwnd;
5874 msg.message = message;
5875 msg.flags = wparam|lparam;
5876 msg.wParam = wParam;
5877 msg.lParam = lParam;
5878 msg.descr = "wmime_keydown";
5879 add_message(&msg);
5880
5881 return DefWindowProcA(hwnd, message, wParam, lParam);
5882 }
5883
5884 static void register_wmime_keydown_class(void)
5885 {
5886 WNDCLASSA cls;
5887
5888 ZeroMemory(&cls, sizeof(WNDCLASSA));
5889 cls.lpfnWndProc = wmime_keydown_procA;
5890 cls.hInstance = GetModuleHandleA(0);
5891 cls.lpszClassName = "wmime_keydown_class";
5892 if (!RegisterClassA(&cls)) assert(0);
5893 }
5894
5895 static void test_wmime_keydown_message(void)
5896 {
5897 HWND hwnd;
5898 MSG msg;
5899
5900 trace("Message sequences by WM_IME_KEYDOWN\n");
5901
5902 register_wmime_keydown_class();
5903 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5904 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5905 NULL, NULL, 0);
5906 flush_events();
5907 flush_sequence();
5908
5909 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5910 SendMessageA(hwnd, WM_CHAR, 'A', 1);
5911 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5912
5913 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
5914 {
5915 TranslateMessage(&msg);
5916 DispatchMessageA(&msg);
5917 }
5918 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5919
5920 DestroyWindow(hwnd);
5921 }
5922
5923 /************* painting message test ********************/
5924
5925 void dump_region(HRGN hrgn)
5926 {
5927 DWORD i, size;
5928 RGNDATA *data = NULL;
5929 RECT *rect;
5930
5931 if (!hrgn)
5932 {
5933 printf( "null region\n" );
5934 return;
5935 }
5936 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5937 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5938 GetRegionData( hrgn, size, data );
5939 printf("%d rects:", data->rdh.nCount );
5940 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5941 printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5942 printf("\n");
5943 HeapFree( GetProcessHeap(), 0, data );
5944 }
5945
5946 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5947 {
5948 INT ret;
5949 RECT r1, r2;
5950 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5951 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5952
5953 ret = GetUpdateRgn( hwnd, update, FALSE );
5954 ok( ret != ERROR, "GetUpdateRgn failed\n" );
5955 if (ret == NULLREGION)
5956 {
5957 ok( !hrgn, "Update region shouldn't be empty\n" );
5958 }
5959 else
5960 {
5961 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5962 {
5963 ok( 0, "Regions are different\n" );
5964 if (winetest_debug > 0)
5965 {
5966 printf( "Update region: " );
5967 dump_region( update );
5968 printf( "Wanted region: " );
5969 dump_region( hrgn );
5970 }
5971 }
5972 }
5973 GetRgnBox( update, &r1 );
5974 GetUpdateRect( hwnd, &r2, FALSE );
5975 ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5976 "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5977 r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5978
5979 DeleteObject( tmp );
5980 DeleteObject( update );
5981 }
5982
5983 static const struct message WmInvalidateRgn[] = {
5984 { WM_NCPAINT, sent },
5985 { WM_GETTEXT, sent|defwinproc|optional },
5986 { 0 }
5987 };
5988
5989 static const struct message WmGetUpdateRect[] = {
5990 { WM_NCPAINT, sent },
5991 { WM_GETTEXT, sent|defwinproc|optional },
5992 { WM_PAINT, sent },
5993 { 0 }
5994 };
5995
5996 static const struct message WmInvalidateFull[] = {
5997 { WM_NCPAINT, sent|wparam, 1 },
5998 { WM_GETTEXT, sent|defwinproc|optional },
5999 { 0 }
6000 };
6001
6002 static const struct message WmInvalidateErase[] = {
6003 { WM_NCPAINT, sent|wparam, 1 },
6004 { WM_GETTEXT, sent|defwinproc|optional },
6005 { WM_ERASEBKGND, sent },
6006 { 0 }
6007 };
6008
6009 static const struct message WmInvalidatePaint[] = {
6010 { WM_PAINT, sent },
6011 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
6012 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6013 { 0 }
6014 };
6015
6016 static const struct message WmInvalidateErasePaint[] = {
6017 { WM_PAINT, sent },
6018 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
6019 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6020 { WM_ERASEBKGND, sent|beginpaint|optional },
6021 { 0 }
6022 };
6023
6024 static const struct message WmInvalidateErasePaint2[] = {
6025 { WM_PAINT, sent },
6026 { WM_NCPAINT, sent|beginpaint },
6027 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6028 { WM_ERASEBKGND, sent|beginpaint|optional },
6029 { 0 }
6030 };
6031
6032 static const struct message WmErase[] = {
6033 { WM_ERASEBKGND, sent },
6034 { 0 }
6035 };
6036
6037 static const struct message WmPaint[] = {
6038 { WM_PAINT, sent },
6039 { 0 }
6040 };
6041
6042 static const struct message WmParentOnlyPaint[] = {
6043 { WM_PAINT, sent|parent },
6044 { 0 }
6045 };
6046
6047 static const struct message WmInvalidateParent[] = {
6048 { WM_NCPAINT, sent|parent },
6049 { WM_GETTEXT, sent|defwinproc|parent|optional },
6050 { WM_ERASEBKGND, sent|parent },
6051 { 0 }
6052 };
6053
6054 static const struct message WmInvalidateParentChild[] = {
6055 { WM_NCPAINT, sent|parent },
6056 { WM_GETTEXT, sent|defwinproc|parent|optional },
6057 { WM_ERASEBKGND, sent|parent },
6058 { WM_NCPAINT, sent },
6059 { WM_GETTEXT, sent|defwinproc|optional },
6060 { WM_ERASEBKGND, sent },
6061 { 0 }
6062 };
6063
6064 static const struct message WmInvalidateParentChild2[] = {
6065 { WM_ERASEBKGND, sent|parent },
6066 { WM_NCPAINT, sent },
6067 { WM_GETTEXT, sent|defwinproc|optional },
6068 { WM_ERASEBKGND, sent },
6069 { 0 }
6070 };
6071
6072 static const struct message WmParentPaint[] = {
6073 { WM_PAINT, sent|parent },
6074 { WM_PAINT, sent },
6075 { 0 }
6076 };
6077
6078 static const struct message WmParentPaintNc[] = {
6079 { WM_PAINT, sent|parent },
6080 { WM_PAINT, sent },
6081 { WM_NCPAINT, sent|beginpaint },
6082 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6083 { WM_ERASEBKGND, sent|beginpaint|optional },
6084 { 0 }
6085 };
6086
6087 static const struct message WmChildPaintNc[] = {
6088 { WM_PAINT, sent },
6089 { WM_NCPAINT, sent|beginpaint },
6090 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6091 { WM_ERASEBKGND, sent|beginpaint|optional },
6092 { 0 }
6093 };
6094
6095 static const struct message WmParentErasePaint[] = {
6096 { WM_PAINT, sent|parent },
6097 { WM_NCPAINT, sent|parent|beginpaint },
6098 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6099 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
6100 { WM_PAINT, sent },
6101 { WM_NCPAINT, sent|beginpaint },
6102 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6103 { WM_ERASEBKGND, sent|beginpaint|optional },
6104 { 0 }
6105 };
6106
6107 static const struct message WmParentOnlyNcPaint[] = {
6108 { WM_PAINT, sent|parent },
6109 { WM_NCPAINT, sent|parent|beginpaint },
6110 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6111 { 0 }
6112 };
6113
6114 static const struct message WmSetParentStyle[] = {
6115 { WM_STYLECHANGING, sent|parent },
6116 { WM_STYLECHANGED, sent|parent },
6117 { 0 }
6118 };
6119
6120 static void test_paint_messages(void)
6121 {
6122 BOOL ret;
6123 RECT rect;
6124 POINT pt;
6125 MSG msg;
6126 HWND hparent, hchild;
6127 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6128 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
6129 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
6130 100, 100, 200, 200, 0, 0, 0, NULL);
6131 ok (hwnd != 0, "Failed to create overlapped window\n");
6132
6133 ShowWindow( hwnd, SW_SHOW );
6134 UpdateWindow( hwnd );
6135 flush_events();
6136 flush_sequence();
6137
6138 check_update_rgn( hwnd, 0 );
6139 SetRectRgn( hrgn, 10, 10, 20, 20 );
6140 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6141 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6142 check_update_rgn( hwnd, hrgn );
6143 SetRectRgn( hrgn2, 20, 20, 30, 30 );
6144 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
6145 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6146 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
6147 check_update_rgn( hwnd, hrgn );
6148 /* validate everything */
6149 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6150 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6151 check_update_rgn( hwnd, 0 );
6152
6153 /* test empty region */
6154 SetRectRgn( hrgn, 10, 10, 10, 15 );
6155 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6156 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6157 check_update_rgn( hwnd, 0 );
6158 /* test empty rect */
6159 SetRect( &rect, 10, 10, 10, 15 );
6160 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
6161 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6162 check_update_rgn( hwnd, 0 );
6163
6164 /* flush pending messages */
6165 flush_events();
6166 flush_sequence();
6167
6168 GetClientRect( hwnd, &rect );
6169 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
6170 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
6171 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6172 */
6173 trace("testing InvalidateRect(0, NULL, FALSE)\n");
6174 SetRectEmpty( &rect );
6175 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
6176 check_update_rgn( hwnd, hrgn );
6177 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6178 flush_events();
6179 ok_sequence( WmPaint, "Paint", FALSE );
6180 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6181 check_update_rgn( hwnd, 0 );
6182
6183 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
6184 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6185 */
6186 trace("testing ValidateRect(0, NULL)\n");
6187 SetRectEmpty( &rect );
6188 if (ValidateRect(0, &rect)) /* not supported on Win9x */
6189 {
6190 check_update_rgn( hwnd, hrgn );
6191 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6192 flush_events();
6193 ok_sequence( WmPaint, "Paint", FALSE );
6194 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6195 check_update_rgn( hwnd, 0 );
6196 }
6197
6198 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
6199 SetLastError(0xdeadbeef);
6200 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
6201 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
6202 "wrong error code %d\n", GetLastError());
6203 check_update_rgn( hwnd, 0 );
6204 flush_events();
6205 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6206
6207 trace("testing ValidateRgn(0, NULL)\n");
6208 SetLastError(0xdeadbeef);
6209 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6210 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6211 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6212 "wrong error code %d\n", GetLastError());
6213 check_update_rgn( hwnd, 0 );
6214 flush_events();
6215 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6216
6217 trace("testing UpdateWindow(NULL)\n");
6218 SetLastError(0xdeadbeef);
6219 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
6220 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6221 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6222 "wrong error code %d\n", GetLastError());
6223 check_update_rgn( hwnd, 0 );
6224 flush_events();
6225 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6226
6227 /* now with frame */
6228 SetRectRgn( hrgn, -5, -5, 20, 20 );
6229
6230 /* flush pending messages */
6231 flush_events();
6232 flush_sequence();
6233 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6234 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6235
6236 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
6237 check_update_rgn( hwnd, hrgn );
6238
6239 flush_sequence();
6240 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6241 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6242
6243 flush_sequence();
6244 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6245 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6246
6247 GetClientRect( hwnd, &rect );
6248 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6249 check_update_rgn( hwnd, hrgn );
6250
6251 flush_sequence();
6252 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6253 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6254
6255 flush_sequence();
6256 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6257 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6258 check_update_rgn( hwnd, 0 );
6259
6260 flush_sequence();
6261 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6262 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6263 check_update_rgn( hwnd, 0 );
6264
6265 flush_sequence();
6266 SetRectRgn( hrgn, 0, 0, 100, 100 );
6267 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6268 SetRectRgn( hrgn, 0, 0, 50, 100 );
6269 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6270 SetRectRgn( hrgn, 50, 0, 100, 100 );
6271 check_update_rgn( hwnd, hrgn );
6272 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6273 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
6274 check_update_rgn( hwnd, 0 );
6275
6276 flush_sequence();
6277 SetRectRgn( hrgn, 0, 0, 100, 100 );
6278 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6279 SetRectRgn( hrgn, 0, 0, 100, 50 );
6280 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6281 ok_sequence( WmErase, "Erase", FALSE );
6282 SetRectRgn( hrgn, 0, 50, 100, 100 );
6283 check_update_rgn( hwnd, hrgn );
6284
6285 flush_sequence();
6286 SetRectRgn( hrgn, 0, 0, 100, 100 );
6287 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6288 SetRectRgn( hrgn, 0, 0, 50, 50 );
6289 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6290 ok_sequence( WmPaint, "Paint", FALSE );
6291
6292 flush_sequence();
6293 SetRectRgn( hrgn, -4, -4, -2, -2 );
6294 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6295 SetRectRgn( hrgn, -200, -200, -198, -198 );
6296 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6297 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6298
6299 flush_sequence();
6300 SetRectRgn( hrgn, -4, -4, -2, -2 );
6301 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6302 SetRectRgn( hrgn, -4, -4, -3, -3 );
6303 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6304 SetRectRgn( hrgn, 0, 0, 1, 1 );
6305 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6306 ok_sequence( WmPaint, "Paint", FALSE );
6307
6308 flush_sequence();
6309 SetRectRgn( hrgn, -4, -4, -1, -1 );
6310 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6311 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6312 /* make sure no WM_PAINT was generated */
6313 flush_events();
6314 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6315
6316 flush_sequence();
6317 SetRectRgn( hrgn, -4, -4, -1, -1 );
6318 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6319 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
6320 {
6321 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6322 {
6323 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6324 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6325 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6326 ret = GetUpdateRect( hwnd, &rect, FALSE );
6327 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6328 /* this will send WM_NCPAINT and validate the non client area */
6329 ret = GetUpdateRect( hwnd, &rect, TRUE );
6330 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6331 }
6332 DispatchMessageA( &msg );
6333 }
6334 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6335
6336 DestroyWindow( hwnd );
6337
6338 /* now test with a child window */
6339
6340 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6341 100, 100, 200, 200, 0, 0, 0, NULL);
6342 ok (hparent != 0, "Failed to create parent window\n");
6343
6344 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6345 10, 10, 100, 100, hparent, 0, 0, NULL);
6346 ok (hchild != 0, "Failed to create child window\n");
6347
6348 ShowWindow( hparent, SW_SHOW );
6349 UpdateWindow( hparent );
6350 UpdateWindow( hchild );
6351 flush_events();
6352 flush_sequence();
6353 log_all_parent_messages++;
6354
6355 SetRect( &rect, 0, 0, 50, 50 );
6356 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6357 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6358 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6359
6360 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6361 pt.x = pt.y = 0;
6362 MapWindowPoints( hchild, hparent, &pt, 1 );
6363 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6364 check_update_rgn( hchild, hrgn );
6365 SetRectRgn( hrgn, 0, 0, 50, 50 );
6366 check_update_rgn( hparent, hrgn );
6367 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6368 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6369 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6370 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6371
6372 flush_events();
6373 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6374
6375 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6376 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6377 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6378 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6379 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6380
6381 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6382 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6383 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6384
6385 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6386 flush_sequence();
6387 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6388 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6389 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6390
6391 /* flush all paint messages */
6392 flush_events();
6393 flush_sequence();
6394
6395 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6396 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6397 SetRectRgn( hrgn, 0, 0, 50, 50 );
6398 check_update_rgn( hparent, hrgn );
6399 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6400 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6401 SetRectRgn( hrgn, 0, 0, 50, 50 );
6402 check_update_rgn( hparent, hrgn );
6403
6404 /* flush all paint messages */
6405 flush_events();
6406 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6407 flush_sequence();
6408
6409 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6410 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6411 SetRectRgn( hrgn, 0, 0, 50, 50 );
6412 check_update_rgn( hparent, hrgn );
6413 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6414 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6415 SetRectRgn( hrgn2, 10, 10, 50, 50 );
6416 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6417 check_update_rgn( hparent, hrgn );
6418 /* flush all paint messages */
6419 flush_events();
6420 flush_sequence();
6421
6422 /* same as above but parent gets completely validated */
6423 SetRect( &rect, 20, 20, 30, 30 );
6424 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6425 SetRectRgn( hrgn, 20, 20, 30, 30 );
6426 check_update_rgn( hparent, hrgn );
6427 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6428 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6429 check_update_rgn( hparent, 0 ); /* no update region */
6430 flush_events();
6431 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
6432
6433 /* make sure RDW_VALIDATE on child doesn't have the same effect */
6434 flush_sequence();
6435 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6436 SetRectRgn( hrgn, 20, 20, 30, 30 );
6437 check_update_rgn( hparent, hrgn );
6438 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6439 SetRectRgn( hrgn, 20, 20, 30, 30 );
6440 check_update_rgn( hparent, hrgn );
6441
6442 /* same as above but normal WM_PAINT doesn't validate parent */
6443 flush_sequence();
6444 SetRect( &rect, 20, 20, 30, 30 );
6445 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6446 SetRectRgn( hrgn, 20, 20, 30, 30 );
6447 check_update_rgn( hparent, hrgn );
6448 /* no WM_PAINT in child while parent still pending */
6449 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6450 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6451 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6452 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6453
6454 flush_sequence();
6455 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6456 /* no WM_PAINT in child while parent still pending */
6457 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6458 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6459 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6460 /* now that parent is valid child should get WM_PAINT */
6461 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6462 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6463 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6464 ok_sequence( WmEmptySeq, "No other message", FALSE );
6465
6466 /* same thing with WS_CLIPCHILDREN in parent */
6467 flush_sequence();
6468 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6469 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6470 /* changing style invalidates non client area, but we need to invalidate something else to see it */
6471 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6472 ok_sequence( WmEmptySeq, "No message", FALSE );
6473 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6474 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6475
6476 flush_sequence();
6477 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6478 SetRectRgn( hrgn, 20, 20, 30, 30 );
6479 check_update_rgn( hparent, hrgn );
6480 /* no WM_PAINT in child while parent still pending */
6481 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6482 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6483 /* WM_PAINT in parent first */
6484 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6485 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6486
6487 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6488 flush_sequence();
6489 SetRect( &rect, 0, 0, 30, 30 );
6490 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6491 SetRectRgn( hrgn, 0, 0, 30, 30 );
6492 check_update_rgn( hparent, hrgn );
6493 flush_events();
6494 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6495
6496 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6497 flush_sequence();
6498 SetRect( &rect, -10, 0, 30, 30 );
6499 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6500 SetRect( &rect, 0, 0, 20, 20 );
6501 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6502 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6503 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6504
6505 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6506 flush_sequence();
6507 SetRect( &rect, -10, 0, 30, 30 );
6508 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6509 SetRect( &rect, 0, 0, 100, 100 );
6510 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6511 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6512 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6513 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6514 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6515
6516 /* test RDW_INTERNALPAINT behavior */
6517
6518 flush_sequence();
6519 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6520 flush_events();
6521 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6522
6523 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6524 flush_events();
6525 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6526
6527 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6528 flush_events();
6529 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6530
6531 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6532 UpdateWindow( hparent );
6533 flush_events();
6534 flush_sequence();
6535 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6536 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6537 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6538 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6539 flush_events();
6540 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6541
6542 UpdateWindow( hparent );
6543 flush_events();
6544 flush_sequence();
6545 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6546 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6547 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6548 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6549 flush_events();
6550 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6551
6552 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6553 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6554 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6555 flush_events();
6556 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6557
6558 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6559 UpdateWindow( hparent );
6560 flush_events();
6561 flush_sequence();
6562 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6563 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6564 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6565 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6566 flush_events();
6567 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6568
6569 UpdateWindow( hparent );
6570 flush_events();
6571 flush_sequence();
6572 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6573 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6574 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6575 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6576 flush_events();
6577 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6578
6579 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6580 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6581
6582 UpdateWindow( hparent );
6583 flush_events();
6584 flush_sequence();
6585 trace("testing SetWindowPos(-10000, -10000) on child\n");
6586 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6587 check_update_rgn( hchild, 0 );
6588 flush_events();
6589
6590 #if 0 /* this one doesn't pass under Wine yet */
6591 UpdateWindow( hparent );
6592 flush_events();
6593 flush_sequence();
6594 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6595 ShowWindow( hchild, SW_MINIMIZE );
6596 check_update_rgn( hchild, 0 );
6597 flush_events();
6598 #endif
6599
6600 UpdateWindow( hparent );
6601 flush_events();
6602 flush_sequence();
6603 trace("testing SetWindowPos(-10000, -10000) on parent\n");
6604 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6605 check_update_rgn( hparent, 0 );
6606 flush_events();
6607
6608 log_all_parent_messages--;
6609 DestroyWindow( hparent );
6610 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6611
6612 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6613
6614 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6615 100, 100, 200, 200, 0, 0, 0, NULL);
6616 ok (hparent != 0, "Failed to create parent window\n");
6617
6618 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6619 10, 10, 100, 100, hparent, 0, 0, NULL);
6620 ok (hchild != 0, "Failed to create child window\n");
6621
6622 ShowWindow( hparent, SW_SHOW );
6623 UpdateWindow( hparent );
6624 UpdateWindow( hchild );
6625 flush_events();
6626 flush_sequence();
6627
6628 /* moving child outside of parent boundaries changes update region */
6629 SetRect( &rect, 0, 0, 40, 40 );
6630 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6631 SetRectRgn( hrgn, 0, 0, 40, 40 );
6632 check_update_rgn( hchild, hrgn );
6633 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6634 SetRectRgn( hrgn, 10, 0, 40, 40 );
6635 check_update_rgn( hchild, hrgn );
6636 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6637 SetRectRgn( hrgn, 10, 10, 40, 40 );
6638 check_update_rgn( hchild, hrgn );
6639
6640 /* moving parent off-screen does too */
6641 SetRect( &rect, 0, 0, 100, 100 );
6642 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6643 SetRectRgn( hrgn, 0, 0, 100, 100 );
6644 check_update_rgn( hparent, hrgn );
6645 SetRectRgn( hrgn, 10, 10, 40, 40 );
6646 check_update_rgn( hchild, hrgn );
6647 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6648 SetRectRgn( hrgn, 20, 20, 100, 100 );
6649 check_update_rgn( hparent, hrgn );
6650 SetRectRgn( hrgn, 30, 30, 40, 40 );
6651 check_update_rgn( hchild, hrgn );
6652
6653 /* invalidated region is cropped by the parent rects */
6654 SetRect( &rect, 0, 0, 50, 50 );
6655 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6656 SetRectRgn( hrgn, 30, 30, 50, 50 );
6657 check_update_rgn( hchild, hrgn );
6658
6659 DestroyWindow( hparent );
6660 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6661 flush_sequence();
6662
6663 DeleteObject( hrgn );
6664 DeleteObject( hrgn2 );
6665 }
6666
6667 struct wnd_event
6668 {
6669 HWND hwnd;
6670 HANDLE grand_child;
6671 HANDLE start_event;
6672 HANDLE stop_event;
6673 };
6674
6675 static DWORD WINAPI thread_proc(void *param)
6676 {
6677 MSG msg;
6678 struct wnd_event *wnd_event = param;
6679
6680 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6681 100, 100, 200, 200, 0, 0, 0, NULL);
6682 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6683
6684 SetEvent(wnd_event->start_event);
6685
6686 while (GetMessageA(&msg, 0, 0, 0))
6687 {
6688 TranslateMessage(&msg);
6689 DispatchMessageA(&msg);
6690 }
6691
6692 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6693
6694 return 0;
6695 }
6696
6697 static DWORD CALLBACK create_grand_child_thread( void *param )
6698 {
6699 struct wnd_event *wnd_event = param;
6700 HWND hchild;
6701 MSG msg;
6702
6703 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6704 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6705 ok (hchild != 0, "Failed to create child window\n");
6706 flush_events();
6707 flush_sequence();
6708 SetEvent( wnd_event->start_event );
6709
6710 for (;;)
6711 {
6712 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6713 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
6714 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6715 }
6716 return 0;
6717 }
6718
6719 static DWORD CALLBACK create_child_thread( void *param )
6720 {
6721 struct wnd_event *wnd_event = param;
6722 struct wnd_event child_event;
6723 DWORD ret, tid;
6724 MSG msg;
6725
6726 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6727 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6728 ok (child_event.hwnd != 0, "Failed to create child window\n");
6729 SetFocus( child_event.hwnd );
6730 flush_events();
6731 flush_sequence();
6732 child_event.start_event = wnd_event->start_event;
6733 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6734 for (;;)
6735 {
6736 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6737 if (ret != 1) break;
6738 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6739 }
6740 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6741 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6742 return 0;
6743 }
6744
6745 static const char manifest_dep[] =
6746 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
6747 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
6748 " <file name=\"testdep.dll\" />"
6749 "</assembly>";
6750
6751 static const char manifest_main[] =
6752 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
6753 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
6754 "<dependency>"
6755 " <dependentAssembly>"
6756 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
6757 " </dependentAssembly>"
6758 "</dependency>"
6759 "</assembly>";
6760
6761 static void create_manifest_file(const char *filename, const char *manifest)
6762 {
6763 WCHAR path[MAX_PATH];
6764 HANDLE file;
6765 DWORD size;
6766
6767 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
6768 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6769 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
6770 WriteFile(file, manifest, strlen(manifest), &size, NULL);
6771 CloseHandle(file);
6772 }
6773
6774 static HANDLE test_create(const char *file)
6775 {
6776 WCHAR path[MAX_PATH];
6777 ACTCTXW actctx;
6778 HANDLE handle;
6779
6780 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
6781 memset(&actctx, 0, sizeof(ACTCTXW));
6782 actctx.cbSize = sizeof(ACTCTXW);
6783 actctx.lpSource = path;
6784
6785 handle = pCreateActCtxW(&actctx);
6786 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
6787
6788 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
6789 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
6790 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
6791 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
6792 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
6793 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
6794 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
6795 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
6796 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
6797
6798 return handle;
6799 }
6800
6801 static void test_interthread_messages(void)
6802 {
6803 HANDLE hThread, context, handle, event;
6804 ULONG_PTR cookie;
6805 DWORD tid;
6806 WNDPROC proc;
6807 MSG msg;
6808 char buf[256];
6809 int len, expected_len;
6810 struct wnd_event wnd_event;
6811 BOOL ret;
6812
6813 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6814 if (!wnd_event.start_event)
6815 {
6816 win_skip("skipping interthread message test under win9x\n");
6817 return;
6818 }
6819
6820 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6821 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6822
6823 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6824
6825 CloseHandle(wnd_event.start_event);
6826
6827 SetLastError(0xdeadbeef);
6828 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
6829 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6830 "wrong error code %d\n", GetLastError());
6831
6832 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6833 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6834
6835 expected_len = lstrlenA("window caption text");
6836 memset(buf, 0, sizeof(buf));
6837 SetLastError(0xdeadbeef);
6838 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6839 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6840 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6841
6842 msg.hwnd = wnd_event.hwnd;
6843 msg.message = WM_GETTEXT;
6844 msg.wParam = sizeof(buf);
6845 msg.lParam = (LPARAM)buf;
6846 memset(buf, 0, sizeof(buf));
6847 SetLastError(0xdeadbeef);
6848 len = DispatchMessageA(&msg);
6849 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6850 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
6851
6852 /* the following test causes an exception in user.exe under win9x */
6853 msg.hwnd = wnd_event.hwnd;
6854 msg.message = WM_TIMER;
6855 msg.wParam = 0;
6856 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6857 SetLastError(0xdeadbeef);
6858 len = DispatchMessageA(&msg);
6859 ok(!len && GetLastError() == 0xdeadbeef,
6860 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6861
6862 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6863 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6864
6865 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6866 CloseHandle(hThread);
6867
6868 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6869
6870 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6871 100, 100, 200, 200, 0, 0, 0, NULL);
6872 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6873 flush_events();
6874 flush_sequence();
6875 log_all_parent_messages++;
6876 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6877 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6878 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6879 for (;;)
6880 {
6881 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6882 if (ret != 1) break;
6883 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6884 }
6885 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6886 /* now wait for the thread without processing messages; this shouldn't deadlock */
6887 SetEvent( wnd_event.stop_event );
6888 ret = WaitForSingleObject( hThread, 5000 );
6889 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6890 CloseHandle( hThread );
6891
6892 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6893 ok( !ret, "WaitForSingleObject failed %x\n", ret );
6894 CloseHandle( wnd_event.grand_child );
6895
6896 CloseHandle( wnd_event.start_event );
6897 CloseHandle( wnd_event.stop_event );
6898 flush_events();
6899 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6900 log_all_parent_messages--;
6901 DestroyWindow( wnd_event.hwnd );
6902
6903 /* activation context tests */
6904 if (!pActivateActCtx)
6905 {
6906 win_skip("Activation contexts are not supported, skipping\n");
6907 return;
6908 }
6909
6910 create_manifest_file("testdep1.manifest", manifest_dep);
6911 create_manifest_file("main.manifest", manifest_main);
6912
6913 context = test_create("main.manifest");
6914 DeleteFileA("testdep1.manifest");
6915 DeleteFileA("main.manifest");
6916
6917 handle = (void*)0xdeadbeef;
6918 ret = pGetCurrentActCtx(&handle);
6919 ok(ret, "GetCurentActCtx failed: %u\n", GetLastError());
6920 ok(handle == 0, "active context %p\n", handle);
6921
6922 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6923 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6924 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6925 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6926 CloseHandle(wnd_event.start_event);
6927
6928 /* context is activated after thread creation, so it doesn't inherit it by default */
6929 ret = pActivateActCtx(context, &cookie);
6930 ok(ret, "activation failed: %u\n", GetLastError());
6931
6932 handle = 0;
6933 ret = pGetCurrentActCtx(&handle);
6934 ok(ret, "GetCurentActCtx failed: %u\n", GetLastError());
6935 ok(handle != 0, "active context %p\n", handle);
6936
6937 /* destination window will test for active context */
6938 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
6939 ok(ret, "thread window returned %d\n", ret);
6940
6941 event = CreateEventW(NULL, 0, 0, NULL);
6942 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
6943 ok(ret, "thread window returned %d\n", ret);
6944 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6945 CloseHandle(event);
6946
6947 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6948 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6949
6950 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6951 CloseHandle(hThread);
6952
6953 ret = pDeactivateActCtx(0, cookie);
6954 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
6955 pReleaseActCtx(context);
6956 }
6957
6958
6959 static const struct message WmVkN[] = {
6960 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6961 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6962 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6963 { WM_CHAR, wparam|lparam, 'n', 1 },
6964 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6965 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6966 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6967 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6968 { 0 }
6969 };
6970 static const struct message WmShiftVkN[] = {
6971 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6972 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6973 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6974 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6975 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6976 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6977 { WM_CHAR, wparam|lparam, 'N', 1 },
6978 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6979 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6980 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6981 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6982 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6983 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6984 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6985 { 0 }
6986 };
6987 static const struct message WmCtrlVkN[] = {
6988 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6989 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6990 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6991 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6992 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6993 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6994 { WM_CHAR, wparam|lparam, 0x000e, 1 },
6995 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6996 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6997 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6998 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6999 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7000 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7001 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7002 { 0 }
7003 };
7004 static const struct message WmCtrlVkN_2[] = {
7005 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7006 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7007 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7008 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7009 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7010 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
7011 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7012 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7013 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7014 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7015 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7016 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7017 { 0 }
7018 };
7019 static const struct message WmAltVkN[] = {
7020 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7021 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7022 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7023 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7024 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
7025 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
7026 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
7027 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
7028 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
7029 { HCBT_SYSCOMMAND, hook },
7030 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7031 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7032 { 0x00AE, sent|defwinproc|optional }, /* XP */
7033 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
7034 { WM_INITMENU, sent|defwinproc },
7035 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7036 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
7037 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7038 { WM_CAPTURECHANGED, sent|defwinproc },
7039 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
7040 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7041 { WM_EXITMENULOOP, sent|defwinproc },
7042 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
7043 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
7044 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7045 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
7046 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7047 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7048 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7049 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7050 { 0 }
7051 };
7052 static const struct message WmAltVkN_2[] = {
7053 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7054 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7055 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7056 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7057 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
7058 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
7059 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7060 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
7061 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7062 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7063 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7064 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7065 { 0 }
7066 };
7067 static const struct message WmCtrlAltVkN[] = {
7068 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7069 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7070 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7071 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7072 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7073 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7074 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7075 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
7076 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
7077 { WM_CHAR, optional },
7078 { WM_CHAR, sent|optional },
7079 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7080 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
7081 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7082 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7083 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7084 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7085 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7086 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7087 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7088 { 0 }
7089 };
7090 static const struct message WmCtrlShiftVkN[] = {
7091 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7092 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7093 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7094 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7095 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7096 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7097 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7098 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7099 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
7100 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7101 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7102 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7103 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7104 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7105 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 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 WmCtrlAltShiftVkN[] = {
7112 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
7113 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
7114 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
7115 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7116 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7117 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7118 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
7119 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
7120 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
7121 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
7122 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
7123 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
7124 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
7125 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
7126 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
7127 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
7128 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
7129 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
7130 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7131 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7132 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7133 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7134 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7135 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7136 { 0 }
7137 };
7138 static const struct message WmAltPressRelease[] = {
7139 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7140 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7141 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7142 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7143 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7144 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7145 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
7146 { HCBT_SYSCOMMAND, hook },
7147 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7148 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7149 { WM_INITMENU, sent|defwinproc },
7150 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7151 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7152 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7153
7154 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
7155
7156 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7157 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7158 { WM_CAPTURECHANGED, sent|defwinproc },
7159 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7160 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7161 { WM_EXITMENULOOP, sent|defwinproc },
7162 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7163 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7164 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7165 { 0 }
7166 };
7167 static const struct message WmShiftMouseButton[] = {
7168 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7169 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7170 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7171 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
7172 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
7173 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
7174 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
7175 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
7176 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
7177 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7178 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7179 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7180 { 0 }
7181 };
7182 static const struct message WmF1Seq[] = {
7183 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
7184 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
7185 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
7186 { WM_KEYF1, wparam|lparam, 0, 0 },
7187 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
7188 { WM_HELP, sent|defwinproc },
7189 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
7190 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
7191 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
7192 { 0 }
7193 };
7194 static const struct message WmVkAppsSeq[] = {
7195 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
7196 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
7197 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
7198 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
7199 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
7200 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
7201 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
7202 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
7203 { 0 }
7204 };
7205 static const struct message WmVkF10Seq[] = {
7206 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7207 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7208 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7209 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7210 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7211 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7212 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7213 { HCBT_SYSCOMMAND, hook },
7214 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7215 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7216 { WM_INITMENU, sent|defwinproc },
7217 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7218 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7219 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7220
7221 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
7222
7223 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7224 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7225 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7226 { WM_CAPTURECHANGED, sent|defwinproc },
7227 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7228 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7229 { WM_EXITMENULOOP, sent|defwinproc },
7230 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7231 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7232 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7233 { 0 }
7234 };
7235 static const struct message WmShiftF10Seq[] = {
7236 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7237 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7238 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
7239 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7240 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7241 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7242 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
7243 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7244 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7245 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7246 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7247 { HCBT_SYSCOMMAND, hook },
7248 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7249 { WM_INITMENU, sent|defwinproc },
7250 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7251 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
7252 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
7253 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
7254 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
7255 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7256 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
7257 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
7258 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
7259 { 0 }
7260 };
7261
7262 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
7263 {
7264 MSG msg;
7265
7266 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
7267 {
7268 struct recvd_message log_msg;
7269
7270 /* ignore some unwanted messages */
7271 if (msg.message == WM_MOUSEMOVE ||
7272 msg.message == WM_TIMER ||
7273 ignore_message( msg.message ))
7274 continue;
7275
7276 log_msg.hwnd = msg.hwnd;
7277 log_msg.message = msg.message;
7278 log_msg.flags = wparam|lparam;
7279 log_msg.wParam = msg.wParam;
7280 log_msg.lParam = msg.lParam;
7281 log_msg.descr = "accel";
7282 add_message(&log_msg);
7283
7284 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
7285 {
7286 TranslateMessage(&msg);
7287 DispatchMessageA(&msg);
7288 }
7289 }
7290 }
7291
7292 static void test_accelerators(void)
7293 {
7294 RECT rc;
7295 POINT pt;
7296 SHORT state;
7297 HACCEL hAccel;
7298 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7299 100, 100, 200, 200, 0, 0, 0, NULL);
7300 BOOL ret;
7301
7302 assert(hwnd != 0);
7303 UpdateWindow(hwnd);
7304 flush_events();
7305 flush_sequence();
7306
7307 SetFocus(hwnd);
7308 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
7309
7310 state = GetKeyState(VK_SHIFT);
7311 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
7312 state = GetKeyState(VK_CAPITAL);
7313 ok(state == 0, "wrong CapsLock state %04x\n", state);
7314
7315 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
7316 assert(hAccel != 0);
7317
7318 flush_events();
7319 pump_msg_loop(hwnd, 0);
7320 flush_sequence();
7321
7322 trace("testing VK_N press/release\n");
7323 flush_sequence();
7324 keybd_event('N', 0, 0, 0);
7325 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7326 pump_msg_loop(hwnd, hAccel);
7327 if (!sequence_cnt) /* we didn't get any message */
7328 {
7329 skip( "queuing key events not supported\n" );
7330 goto done;
7331 }
7332 ok_sequence(WmVkN, "VK_N press/release", FALSE);
7333
7334 trace("testing Shift+VK_N press/release\n");
7335 flush_sequence();
7336 keybd_event(VK_SHIFT, 0, 0, 0);
7337 keybd_event('N', 0, 0, 0);
7338 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7339 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7340 pump_msg_loop(hwnd, hAccel);
7341 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7342
7343 trace("testing Ctrl+VK_N press/release\n");
7344 flush_sequence();
7345 keybd_event(VK_CONTROL, 0, 0, 0);
7346 keybd_event('N', 0, 0, 0);
7347 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7348 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7349 pump_msg_loop(hwnd, hAccel);
7350 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
7351
7352 trace("testing Alt+VK_N press/release\n");
7353 flush_sequence();
7354 keybd_event(VK_MENU, 0, 0, 0);
7355 keybd_event('N', 0, 0, 0);
7356 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7357 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7358 pump_msg_loop(hwnd, hAccel);
7359 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
7360
7361 trace("testing Ctrl+Alt+VK_N press/release 1\n");
7362 flush_sequence();
7363 keybd_event(VK_CONTROL, 0, 0, 0);
7364 keybd_event(VK_MENU, 0, 0, 0);
7365 keybd_event('N', 0, 0, 0);
7366 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7367 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7368 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7369 pump_msg_loop(hwnd, hAccel);
7370 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
7371
7372 ret = DestroyAcceleratorTable(hAccel);
7373 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7374
7375 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
7376 assert(hAccel != 0);
7377
7378 trace("testing VK_N press/release\n");
7379 flush_sequence();
7380 keybd_event('N', 0, 0, 0);
7381 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7382 pump_msg_loop(hwnd, hAccel);
7383 ok_sequence(WmVkN, "VK_N press/release", FALSE);
7384
7385 trace("testing Shift+VK_N press/release\n");
7386 flush_sequence();
7387 keybd_event(VK_SHIFT, 0, 0, 0);
7388 keybd_event('N', 0, 0, 0);
7389 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7390 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7391 pump_msg_loop(hwnd, hAccel);
7392 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7393
7394 trace("testing Ctrl+VK_N press/release 2\n");
7395 flush_sequence();
7396 keybd_event(VK_CONTROL, 0, 0, 0);
7397 keybd_event('N', 0, 0, 0);
7398 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7399 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7400 pump_msg_loop(hwnd, hAccel);
7401 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7402
7403 trace("testing Alt+VK_N press/release 2\n");
7404 flush_sequence();
7405 keybd_event(VK_MENU, 0, 0, 0);
7406 keybd_event('N', 0, 0, 0);
7407 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7408 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7409 pump_msg_loop(hwnd, hAccel);
7410 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7411
7412 trace("testing Ctrl+Alt+VK_N press/release 2\n");
7413 flush_sequence();
7414 keybd_event(VK_CONTROL, 0, 0, 0);
7415 keybd_event(VK_MENU, 0, 0, 0);
7416 keybd_event('N', 0, 0, 0);
7417 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7418 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7419 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7420 pump_msg_loop(hwnd, hAccel);
7421 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7422
7423 trace("testing Ctrl+Shift+VK_N press/release\n");
7424 flush_sequence();
7425 keybd_event(VK_CONTROL, 0, 0, 0);
7426 keybd_event(VK_SHIFT, 0, 0, 0);
7427 keybd_event('N', 0, 0, 0);
7428 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7429 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7430 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7431 pump_msg_loop(hwnd, hAccel);
7432 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7433
7434 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7435 flush_sequence();
7436 keybd_event(VK_CONTROL, 0, 0, 0);
7437 keybd_event(VK_MENU, 0, 0, 0);
7438 keybd_event(VK_SHIFT, 0, 0, 0);
7439 keybd_event('N', 0, 0, 0);
7440 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7441 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7442 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7443 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7444 pump_msg_loop(hwnd, hAccel);
7445 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7446
7447 ret = DestroyAcceleratorTable(hAccel);
7448 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7449 hAccel = 0;
7450
7451 trace("testing Alt press/release\n");
7452 flush_sequence();
7453 keybd_event(VK_MENU, 0, 0, 0);
7454 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7455 keybd_event(VK_MENU, 0, 0, 0);
7456 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7457 pump_msg_loop(hwnd, 0);
7458 /* this test doesn't pass in Wine for managed windows */
7459 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7460
7461 trace("testing VK_F1 press/release\n");
7462 keybd_event(VK_F1, 0, 0, 0);
7463 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7464 pump_msg_loop(hwnd, 0);
7465 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7466
7467 trace("testing VK_APPS press/release\n");
7468 keybd_event(VK_APPS, 0, 0, 0);
7469 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7470 pump_msg_loop(hwnd, 0);
7471 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7472
7473 trace("testing VK_F10 press/release\n");
7474 keybd_event(VK_F10, 0, 0, 0);
7475 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7476 keybd_event(VK_F10, 0, 0, 0);
7477 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7478 pump_msg_loop(hwnd, 0);
7479 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
7480
7481 trace("testing SHIFT+F10 press/release\n");
7482 keybd_event(VK_SHIFT, 0, 0, 0);
7483 keybd_event(VK_F10, 0, 0, 0);
7484 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7485 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7486 keybd_event(VK_ESCAPE, 0, 0, 0);
7487 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
7488 pump_msg_loop(hwnd, 0);
7489 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
7490
7491 trace("testing Shift+MouseButton press/release\n");
7492 /* first, move mouse pointer inside of the window client area */
7493 GetClientRect(hwnd, &rc);
7494 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7495 rc.left += (rc.right - rc.left)/2;
7496 rc.top += (rc.bottom - rc.top)/2;
7497 SetCursorPos(rc.left, rc.top);
7498 SetActiveWindow(hwnd);
7499
7500 flush_events();
7501 flush_sequence();
7502 GetCursorPos(&pt);
7503 if (pt.x == rc.left && pt.y == rc.top)
7504 {
7505 int i;
7506 keybd_event(VK_SHIFT, 0, 0, 0);
7507 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7508 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7509 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7510 pump_msg_loop(hwnd, 0);
7511 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7512 if (i < sequence_cnt)
7513 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7514 else
7515 skip( "Shift+MouseButton event didn't get to the window\n" );
7516 }
7517
7518 done:
7519 if (hAccel) DestroyAcceleratorTable(hAccel);
7520 DestroyWindow(hwnd);
7521 }
7522
7523 /************* window procedures ********************/
7524
7525 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
7526 WPARAM wParam, LPARAM lParam)
7527 {
7528 static LONG defwndproc_counter = 0;
7529 static LONG beginpaint_counter = 0;
7530 LRESULT ret;
7531 struct recvd_message msg;
7532
7533 if (ignore_message( message )) return 0;
7534
7535 switch (message)
7536 {
7537 case WM_ENABLE:
7538 {
7539 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7540 ok((BOOL)wParam == !(style & WS_DISABLED),
7541 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7542 break;
7543 }
7544
7545 case WM_CAPTURECHANGED:
7546 if (test_DestroyWindow_flag)
7547 {
7548 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7549 if (style & WS_CHILD)
7550 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7551 else if (style & WS_POPUP)
7552 lParam = WND_POPUP_ID;
7553 else
7554 lParam = WND_PARENT_ID;
7555 }
7556 break;
7557
7558 case WM_NCDESTROY:
7559 {
7560 HWND capture;
7561
7562 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7563 capture = GetCapture();
7564 if (capture)
7565 {
7566 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7567 trace("current capture %p, releasing...\n", capture);
7568 ReleaseCapture();
7569 }
7570 }
7571 /* fall through */
7572 case WM_DESTROY:
7573 if (pGetAncestor)
7574 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7575 if (test_DestroyWindow_flag)
7576 {
7577 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7578 if (style & WS_CHILD)
7579 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7580 else if (style & WS_POPUP)
7581 lParam = WND_POPUP_ID;
7582 else
7583 lParam = WND_PARENT_ID;
7584 }
7585 break;
7586
7587 /* test_accelerators() depends on this */
7588 case WM_NCHITTEST:
7589 return HTCLIENT;
7590
7591 case WM_USER+10:
7592 {
7593 HANDLE handle, event = (HANDLE)lParam;
7594 BOOL ret;
7595
7596 handle = (void*)0xdeadbeef;
7597 ret = pGetCurrentActCtx(&handle);
7598 ok(ret, "failed to get current context, %u\n", GetLastError());
7599 ok(handle == 0, "got active context %p\n", handle);
7600 if (event) SetEvent(event);
7601 return 1;
7602 }
7603
7604 /* ignore */
7605 case WM_MOUSEMOVE:
7606 case WM_MOUSEACTIVATE:
7607 case WM_NCMOUSEMOVE:
7608 case WM_SETCURSOR:
7609 case WM_IME_SELECT:
7610 return 0;
7611 }
7612
7613 msg.hwnd = hwnd;
7614 msg.message = message;
7615 msg.flags = sent|wparam|lparam;
7616 if (defwndproc_counter) msg.flags |= defwinproc;
7617 if (beginpaint_counter) msg.flags |= beginpaint;
7618 msg.wParam = wParam;
7619 msg.lParam = lParam;
7620 msg.descr = "MsgCheckProc";
7621 add_message(&msg);
7622
7623 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7624 {
7625 HWND parent = GetParent(hwnd);
7626 RECT rc;
7627 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7628
7629 GetClientRect(parent, &rc);
7630 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7631 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7632 minmax->ptReserved.x, minmax->ptReserved.y,
7633 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7634 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7635 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7636 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7637
7638 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7639 minmax->ptMaxSize.x, rc.right);
7640 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7641 minmax->ptMaxSize.y, rc.bottom);
7642 }
7643
7644 if (message == WM_PAINT)
7645 {
7646 PAINTSTRUCT ps;
7647 beginpaint_counter++;
7648 BeginPaint( hwnd, &ps );
7649 beginpaint_counter--;
7650 EndPaint( hwnd, &ps );
7651 return 0;
7652 }
7653
7654 defwndproc_counter++;
7655 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
7656 : DefWindowProcA(hwnd, message, wParam, lParam);
7657 defwndproc_counter--;
7658
7659 return ret;
7660 }
7661
7662 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7663 {
7664 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7665 }
7666
7667 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7668 {
7669 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7670 }
7671
7672 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7673 {
7674 static LONG defwndproc_counter = 0;
7675 LRESULT ret;
7676 struct recvd_message msg;
7677
7678 if (ignore_message( message )) return 0;
7679
7680 switch (message)
7681 {
7682 case WM_QUERYENDSESSION:
7683 case WM_ENDSESSION:
7684 lParam &= ~0x01; /* Vista adds a 0x01 flag */
7685 break;
7686 }
7687
7688 msg.hwnd = hwnd;
7689 msg.message = message;
7690 msg.flags = sent|wparam|lparam;
7691 if (defwndproc_counter) msg.flags |= defwinproc;
7692 msg.wParam = wParam;
7693 msg.lParam = lParam;
7694 msg.descr = "popup";
7695 add_message(&msg);
7696
7697 if (message == WM_CREATE)
7698 {
7699 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7700 SetWindowLongA(hwnd, GWL_STYLE, style);
7701 }
7702
7703 defwndproc_counter++;
7704 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7705 defwndproc_counter--;
7706
7707 return ret;
7708 }
7709
7710 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7711 {
7712 static LONG defwndproc_counter = 0;
7713 static LONG beginpaint_counter = 0;
7714 LRESULT ret;
7715 struct recvd_message msg;
7716
7717 if (ignore_message( message )) return 0;
7718
7719 if (log_all_parent_messages ||
7720 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7721 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7722 message == WM_ENABLE || message == WM_ENTERIDLE ||
7723 message == WM_DRAWITEM || message == WM_COMMAND ||
7724 message == WM_IME_SETCONTEXT)
7725 {
7726 switch (message)
7727 {
7728 /* ignore */
7729 case WM_NCHITTEST:
7730 return HTCLIENT;
7731 case WM_SETCURSOR:
7732 case WM_MOUSEMOVE:
7733 case WM_NCMOUSEMOVE:
7734 return 0;
7735
7736 case WM_ERASEBKGND:
7737 {
7738 RECT rc;
7739 INT ret = GetClipBox((HDC)wParam, &rc);
7740
7741 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7742 ret, rc.left, rc.top, rc.right, rc.bottom);
7743 break;
7744 }
7745 }
7746
7747 msg.hwnd = hwnd;
7748 msg.message = message;
7749 msg.flags = sent|parent|wparam|lparam;
7750 if (defwndproc_counter) msg.flags |= defwinproc;
7751 if (beginpaint_counter) msg.flags |= beginpaint;
7752 msg.wParam = wParam;
7753 msg.lParam = lParam;
7754 msg.descr = "parent";
7755 add_message(&msg);
7756 }
7757
7758 if (message == WM_PAINT)
7759 {
7760 PAINTSTRUCT ps;
7761 beginpaint_counter++;
7762 BeginPaint( hwnd, &ps );
7763 beginpaint_counter--;
7764 EndPaint( hwnd, &ps );
7765 return 0;
7766 }
7767
7768 defwndproc_counter++;
7769 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7770 defwndproc_counter--;
7771
7772 return ret;
7773 }
7774
7775 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
7776 {
7777 if (message == WM_CREATE)
7778 PostMessageA(hwnd, WM_CLOSE, 0, 0);
7779 else if (message == WM_CLOSE)
7780 {
7781 /* Only the first WM_QUIT will survive the window destruction */
7782 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
7783 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
7784 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
7785 }
7786
7787 return DefWindowProcA(hwnd, message, wp, lp);
7788 }
7789
7790 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7791 {
7792 static LONG defwndproc_counter = 0;
7793 LRESULT ret;
7794 struct recvd_message msg;
7795
7796 if (ignore_message( message )) return 0;
7797
7798 if (test_def_id)
7799 {
7800 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7801 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7802 if (after_end_dialog)
7803 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7804 else
7805 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7806 }
7807
7808 msg.hwnd = hwnd;
7809 msg.message = message;
7810 msg.flags = sent|wparam|lparam;
7811 if (defwndproc_counter) msg.flags |= defwinproc;
7812 msg.wParam = wParam;
7813 msg.lParam = lParam;
7814 msg.descr = "dialog";
7815 add_message(&msg);
7816
7817 defwndproc_counter++;
7818 ret = DefDlgProcA(hwnd, message, wParam, lParam);
7819 defwndproc_counter--;
7820
7821 return ret;
7822 }
7823
7824 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7825 {
7826 static LONG defwndproc_counter = 0;
7827 LRESULT ret;
7828 struct recvd_message msg;
7829
7830 /* log only specific messages we are interested in */
7831 switch (message)
7832 {
7833 #if 0 /* probably log these as well */
7834 case WM_ACTIVATE:
7835 case WM_SETFOCUS:
7836 case WM_KILLFOCUS:
7837 #endif
7838 case WM_SHOWWINDOW:
7839 case WM_SIZE:
7840 case WM_MOVE:
7841 case WM_GETMINMAXINFO:
7842 case WM_WINDOWPOSCHANGING:
7843 case WM_WINDOWPOSCHANGED:
7844 break;
7845
7846 default: /* ignore */
7847 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7848 return DefWindowProcA(hwnd, message, wParam, lParam);
7849 }
7850
7851 msg.hwnd = hwnd;
7852 msg.message = message;
7853 msg.flags = sent|wparam|lparam;
7854 if (defwndproc_counter) msg.flags |= defwinproc;
7855 msg.wParam = wParam;
7856 msg.lParam = lParam;
7857 msg.descr = "show";
7858 add_message(&msg);
7859
7860 defwndproc_counter++;
7861 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7862 defwndproc_counter--;
7863
7864 return ret;
7865 }
7866
7867 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7868 {
7869 switch (msg)
7870 {
7871 case WM_CREATE: return 0;
7872 case WM_PAINT:
7873 {
7874 MSG msg2;
7875 static int i = 0;
7876
7877 if (i < 256)
7878 {
7879 i++;
7880 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7881 {
7882 TranslateMessage(&msg2);
7883 DispatchMessageA(&msg2);
7884 }
7885 i--;
7886 }
7887 else ok(broken(1), "infinite loop\n");
7888 if ( i == 0)
7889 paint_loop_done = 1;
7890 return DefWindowProcA(hWnd,msg,wParam,lParam);
7891 }
7892 }
7893 return DefWindowProcA(hWnd,msg,wParam,lParam);
7894 }
7895
7896 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7897 {
7898 static LONG defwndproc_counter = 0;
7899 LRESULT ret;
7900 struct recvd_message msg;
7901 DWORD queue_status;
7902
7903 if (ignore_message( message )) return 0;
7904
7905 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
7906 message == WM_HOTKEY || message >= WM_APP)
7907 {
7908 msg.hwnd = hwnd;
7909 msg.message = message;
7910 msg.flags = sent|wparam|lparam;
7911 if (defwndproc_counter) msg.flags |= defwinproc;
7912 msg.wParam = wParam;
7913 msg.lParam = lParam;
7914 msg.descr = "HotkeyMsgCheckProcA";
7915 add_message(&msg);
7916 }
7917
7918 defwndproc_counter++;
7919 ret = DefWindowProcA(hwnd, message, wParam, lParam);
7920 defwndproc_counter--;
7921
7922 if (message == WM_APP)
7923 {
7924 queue_status = GetQueueStatus(QS_HOTKEY);
7925 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
7926 queue_status = GetQueueStatus(QS_POSTMESSAGE);
7927 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
7928 PostMessageA(hwnd, WM_APP+1, 0, 0);
7929 }
7930 else if (message == WM_APP+1)
7931 {
7932 queue_status = GetQueueStatus(QS_HOTKEY);
7933 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
7934 }
7935
7936 return ret;
7937 }
7938
7939 static BOOL RegisterWindowClasses(void)
7940 {
7941 WNDCLASSA cls;
7942 WNDCLASSW clsW;
7943
7944 cls.style = 0;
7945 cls.lpfnWndProc = MsgCheckProcA;
7946 cls.cbClsExtra = 0;
7947 cls.cbWndExtra = 0;
7948 cls.hInstance = GetModuleHandleA(0);
7949 cls.hIcon = 0;
7950 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
7951 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7952 cls.lpszMenuName = NULL;
7953 cls.lpszClassName = "TestWindowClass";
7954 if(!RegisterClassA(&cls)) return FALSE;
7955
7956 cls.lpfnWndProc = HotkeyMsgCheckProcA;
7957 cls.lpszClassName = "HotkeyWindowClass";
7958 if(!RegisterClassA(&cls)) return FALSE;
7959
7960 cls.lpfnWndProc = ShowWindowProcA;
7961 cls.lpszClassName = "ShowWindowClass";
7962 if(!RegisterClassA(&cls)) return FALSE;
7963
7964 cls.lpfnWndProc = PopupMsgCheckProcA;
7965 cls.lpszClassName = "TestPopupClass";
7966 if(!RegisterClassA(&cls)) return FALSE;
7967
7968 cls.lpfnWndProc = ParentMsgCheckProcA;
7969 cls.lpszClassName = "TestParentClass";
7970 if(!RegisterClassA(&cls)) return FALSE;
7971
7972 cls.lpfnWndProc = StopQuitMsgCheckProcA;
7973 cls.lpszClassName = "StopQuitClass";
7974 if(!RegisterClassA(&cls)) return FALSE;
7975
7976 cls.lpfnWndProc = DefWindowProcA;
7977 cls.lpszClassName = "SimpleWindowClass";
7978 if(!RegisterClassA(&cls)) return FALSE;
7979
7980 cls.lpfnWndProc = PaintLoopProcA;
7981 cls.lpszClassName = "PaintLoopWindowClass";
7982 if(!RegisterClassA(&cls)) return FALSE;
7983
7984 cls.style = CS_NOCLOSE;
7985 cls.lpszClassName = "NoCloseWindowClass";
7986 if(!RegisterClassA(&cls)) return FALSE;
7987
7988 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7989 cls.style = 0;
7990 cls.hInstance = GetModuleHandleA(0);
7991 cls.hbrBackground = 0;
7992 cls.lpfnWndProc = TestDlgProcA;
7993 cls.lpszClassName = "TestDialogClass";
7994 if(!RegisterClassA(&cls)) return FALSE;
7995
7996 clsW.style = 0;
7997 clsW.lpfnWndProc = MsgCheckProcW;
7998 clsW.cbClsExtra = 0;
7999 clsW.cbWndExtra = 0;
8000 clsW.hInstance = GetModuleHandleW(0);
8001 clsW.hIcon = 0;
8002 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
8003 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
8004 clsW.lpszMenuName = NULL;
8005 clsW.lpszClassName = testWindowClassW;
8006 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
8007
8008 return TRUE;
8009 }
8010
8011 static BOOL is_our_logged_class(HWND hwnd)
8012 {
8013 char buf[256];
8014
8015 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8016 {
8017 if (!lstrcmpiA(buf, "TestWindowClass") ||
8018 !lstrcmpiA(buf, "ShowWindowClass") ||
8019 !lstrcmpiA(buf, "TestParentClass") ||
8020 !lstrcmpiA(buf, "TestPopupClass") ||
8021 !lstrcmpiA(buf, "SimpleWindowClass") ||
8022 !lstrcmpiA(buf, "TestDialogClass") ||
8023 !lstrcmpiA(buf, "MDI_frame_class") ||
8024 !lstrcmpiA(buf, "MDI_client_class") ||
8025 !lstrcmpiA(buf, "MDI_child_class") ||
8026 !lstrcmpiA(buf, "my_button_class") ||
8027 !lstrcmpiA(buf, "my_edit_class") ||
8028 !lstrcmpiA(buf, "static") ||
8029 !lstrcmpiA(buf, "ListBox") ||
8030 !lstrcmpiA(buf, "ComboBox") ||
8031 !lstrcmpiA(buf, "MyDialogClass") ||
8032 !lstrcmpiA(buf, "#32770") ||
8033 !lstrcmpiA(buf, "#32768"))
8034 return TRUE;
8035 }
8036 return FALSE;
8037 }
8038
8039 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
8040 {
8041 HWND hwnd;
8042
8043 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
8044
8045 if (nCode == HCBT_CLICKSKIPPED)
8046 {
8047 /* ignore this event, XP sends it a lot when switching focus between windows */
8048 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8049 }
8050
8051 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
8052 {
8053 struct recvd_message msg;
8054
8055 msg.hwnd = 0;
8056 msg.message = nCode;
8057 msg.flags = hook|wparam|lparam;
8058 msg.wParam = wParam;
8059 msg.lParam = lParam;
8060 msg.descr = "CBT";
8061 add_message(&msg);
8062
8063 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8064 }
8065
8066 if (nCode == HCBT_DESTROYWND)
8067 {
8068 if (test_DestroyWindow_flag)
8069 {
8070 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
8071 if (style & WS_CHILD)
8072 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
8073 else if (style & WS_POPUP)
8074 lParam = WND_POPUP_ID;
8075 else
8076 lParam = WND_PARENT_ID;
8077 }
8078 }
8079
8080 /* Log also SetFocus(0) calls */
8081 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8082
8083 if (is_our_logged_class(hwnd))
8084 {
8085 struct recvd_message msg;
8086
8087 msg.hwnd = hwnd;
8088 msg.message = nCode;
8089 msg.flags = hook|wparam|lparam;
8090 msg.wParam = wParam;
8091 msg.lParam = lParam;
8092 msg.descr = "CBT";
8093 add_message(&msg);
8094 }
8095 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
8096 }
8097
8098 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
8099 DWORD event,
8100 HWND hwnd,
8101 LONG object_id,
8102 LONG child_id,
8103 DWORD thread_id,
8104 DWORD event_time)
8105 {
8106 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
8107
8108 /* ignore mouse cursor events */
8109 if (object_id == OBJID_CURSOR) return;
8110
8111 if (!hwnd || is_our_logged_class(hwnd))
8112 {
8113 struct recvd_message msg;
8114
8115 msg.hwnd = hwnd;
8116 msg.message = event;
8117 msg.flags = winevent_hook|wparam|lparam;
8118 msg.wParam = object_id;
8119 msg.lParam = child_id;
8120 msg.descr = "WEH";
8121 add_message(&msg);
8122 }
8123 }
8124
8125 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
8126 static const WCHAR wszAnsi[] = {'U',0};
8127
8128 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
8129 {
8130 switch (uMsg)
8131 {
8132 case CB_FINDSTRINGEXACT:
8133 trace("String: %p\n", (LPCWSTR)lParam);
8134 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
8135 return 1;
8136 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
8137 return 0;
8138 return -1;
8139 }
8140 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
8141 }
8142
8143 static const struct message WmGetTextLengthAfromW[] = {
8144 { WM_GETTEXTLENGTH, sent },
8145 { WM_GETTEXT, sent|optional },
8146 { 0 }
8147 };
8148
8149 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
8150
8151 /* dummy window proc for WM_GETTEXTLENGTH test */
8152 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
8153 {
8154 switch(msg)
8155 {
8156 case WM_GETTEXTLENGTH:
8157 return lstrlenW(dummy_window_text) + 37; /* some random length */
8158 case WM_GETTEXT:
8159 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
8160 return lstrlenW( (LPWSTR)lp );
8161 default:
8162 return DefWindowProcW( hwnd, msg, wp, lp );
8163 }
8164 }
8165
8166 static void test_message_conversion(void)
8167 {
8168 static const WCHAR wszMsgConversionClass[] =
8169 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
8170 WNDCLASSW cls;
8171 LRESULT lRes;
8172 HWND hwnd;
8173 WNDPROC wndproc, newproc;
8174 BOOL ret;
8175
8176 cls.style = 0;
8177 cls.lpfnWndProc = MsgConversionProcW;
8178 cls.cbClsExtra = 0;
8179 cls.cbWndExtra = 0;
8180 cls.hInstance = GetModuleHandleW(NULL);
8181 cls.hIcon = NULL;
8182 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
8183 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
8184 cls.lpszMenuName = NULL;
8185 cls.lpszClassName = wszMsgConversionClass;
8186 /* this call will fail on Win9x, but that doesn't matter as this test is
8187 * meaningless on those platforms */
8188 if(!RegisterClassW(&cls)) return;
8189
8190 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
8191 100, 100, 200, 200, 0, 0, 0, NULL);
8192 ok(hwnd != NULL, "Window creation failed\n");
8193
8194 /* {W, A} -> A */
8195
8196 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
8197 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8198 ok(lRes == 0, "String should have been converted\n");
8199 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8200 ok(lRes == 1, "String shouldn't have been converted\n");
8201
8202 /* {W, A} -> W */
8203
8204 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
8205 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8206 ok(lRes == 1, "String shouldn't have been converted\n");
8207 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8208 ok(lRes == 1, "String shouldn't have been converted\n");
8209
8210 /* Synchronous messages */
8211
8212 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8213 ok(lRes == 0, "String should have been converted\n");
8214 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8215 ok(lRes == 1, "String shouldn't have been converted\n");
8216
8217 /* Asynchronous messages */
8218
8219 SetLastError(0);
8220 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8221 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8222 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8223 SetLastError(0);
8224 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8225 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8226 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8227 SetLastError(0);
8228 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8229 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8230 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8231 SetLastError(0);
8232 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8233 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8234 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8235 SetLastError(0);
8236 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8237 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8238 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8239 SetLastError(0);
8240 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8241 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8242 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8243 SetLastError(0);
8244 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8245 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8246 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8247 SetLastError(0);
8248 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8249 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8250 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8251
8252 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
8253
8254 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
8255 WS_OVERLAPPEDWINDOW,
8256 100, 100, 200, 200, 0, 0, 0, NULL);
8257 assert(hwnd);
8258 flush_sequence();
8259 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
8260 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8261 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8262 "got bad length %ld\n", lRes );
8263
8264 flush_sequence();
8265 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
8266 hwnd, WM_GETTEXTLENGTH, 0, 0);
8267 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8268 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8269 "got bad length %ld\n", lRes );
8270
8271 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
8272 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
8273 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8274 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8275 NULL, 0, NULL, NULL ) ||
8276 broken(lRes == lstrlenW(dummy_window_text) + 37),
8277 "got bad length %ld\n", lRes );
8278
8279 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
8280 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8281 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8282 NULL, 0, NULL, NULL ) ||
8283 broken(lRes == lstrlenW(dummy_window_text) + 37),
8284 "got bad length %ld\n", lRes );
8285
8286 ret = DestroyWindow(hwnd);
8287 ok( ret, "DestroyWindow() error %d\n", GetLastError());
8288 }
8289
8290 struct timer_info
8291 {
8292 HWND hWnd;
8293 HANDLE handles[2];
8294 DWORD id;
8295 };
8296
8297 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8298 {
8299 }
8300
8301 #define TIMER_ID 0x19
8302 #define TIMER_COUNT_EXPECTED 64
8303 #define TIMER_COUNT_TOLERANCE 9
8304
8305 static int count = 0;
8306 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
8307 {
8308 count++;
8309 }
8310
8311 static DWORD WINAPI timer_thread_proc(LPVOID x)
8312 {
8313 struct timer_info *info = x;
8314 DWORD r;
8315
8316 r = KillTimer(info->hWnd, 0x19);
8317 ok(r,"KillTimer failed in thread\n");
8318 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
8319 ok(r,"SetTimer failed in thread\n");
8320 ok(r==TIMER_ID,"SetTimer id different\n");
8321 r = SetEvent(info->handles[0]);
8322 ok(r,"SetEvent failed in thread\n");
8323 return 0;
8324 }
8325
8326 static void test_timers(void)
8327 {
8328 struct timer_info info;
8329 DWORD start;
8330 DWORD id;
8331 MSG msg;
8332
8333 info.hWnd = CreateWindowA("TestWindowClass", NULL,
8334 WS_OVERLAPPEDWINDOW ,
8335 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8336 NULL, NULL, 0);
8337
8338 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
8339 ok(info.id, "SetTimer failed\n");
8340 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
8341 info.handles[0] = CreateEventW(NULL,0,0,NULL);
8342 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
8343
8344 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
8345
8346 WaitForSingleObject(info.handles[1], INFINITE);
8347
8348 CloseHandle(info.handles[0]);
8349 CloseHandle(info.handles[1]);
8350
8351 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
8352
8353 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
8354 * but testing indicates that the minimum timeout is actually about 15.6 ms. Since there is
8355 * some measurement error between test runs we're allowing for ±8 counts (~2 ms).
8356 */
8357 count = 0;
8358 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
8359 ok(id != 0, "did not get id from SetTimer.\n");
8360 ok(id==TIMER_ID, "SetTimer timer ID different\n");
8361 start = GetTickCount();
8362 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
8363 DispatchMessageA(&msg);
8364 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
8365 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3 */,
8366 "did not get expected count for minimum timeout (%d != ~%d).\n",
8367 count, TIMER_COUNT_EXPECTED);
8368 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
8369 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
8370 if (pSetSystemTimer)
8371 {
8372 int syscount = 0;
8373
8374 count = 0;
8375 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
8376 ok(id != 0, "did not get id from SetSystemTimer.\n");
8377 ok(id==TIMER_ID, "SetTimer timer ID different\n");
8378 start = GetTickCount();
8379 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
8380 {
8381 if (msg.message == WM_SYSTIMER)
8382 syscount++;
8383 DispatchMessageA(&msg);
8384 }
8385 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE,
8386 "did not get expected count for minimum timeout (%d != ~%d).\n",
8387 syscount, TIMER_COUNT_EXPECTED);
8388 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
8389 count);
8390 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
8391 }
8392
8393 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8394 }
8395
8396 static void test_timers_no_wnd(void)
8397 {
8398 UINT_PTR id, id2;
8399 DWORD start;
8400 MSG msg;
8401
8402 count = 0;
8403 id = SetTimer(NULL, 0, 100, callback_count);
8404 ok(id != 0, "did not get id from SetTimer.\n");
8405 id2 = SetTimer(NULL, id, 200, callback_count);
8406 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
8407 Sleep(150);
8408 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8409 ok(count == 0, "did not get zero count as expected (%i).\n", count);
8410 Sleep(150);
8411 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8412 ok(count == 1, "did not get one count as expected (%i).\n", count);
8413 KillTimer(NULL, id);
8414 Sleep(250);
8415 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8416 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
8417
8418 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
8419 * but testing indicates that the minimum timeout is actually about 15.6 ms. Since there is
8420 * some measurement error between test runs we're allowing for ±8 counts (~2 ms).
8421 */
8422 count = 0;
8423 id = SetTimer(NULL, 0, 0, callback_count);
8424 ok(id != 0, "did not get id from SetTimer.\n");
8425 start = GetTickCount();
8426 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
8427 DispatchMessageA(&msg);
8428 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE,
8429 "did not get expected count for minimum timeout (%d != ~%d).\n",
8430 count, TIMER_COUNT_EXPECTED);
8431 KillTimer(NULL, id);
8432 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
8433 }
8434
8435 /* Various win events with arbitrary parameters */
8436 static const struct message WmWinEventsSeq[] = {
8437 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8438 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8439 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8440 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8441 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8442 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8443 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8444 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8445 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8446 /* our win event hook ignores OBJID_CURSOR events */
8447 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
8448 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
8449 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
8450 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
8451 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
8452 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8453 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8454 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8455 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8456 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8457 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8458 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8459 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8460 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8461 { 0 }
8462 };
8463 static const struct message WmWinEventCaretSeq[] = {
8464 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8465 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8466 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
8467 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8468 { 0 }
8469 };
8470 static const struct message WmWinEventCaretSeq_2[] = {
8471 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8472 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8473 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8474 { 0 }
8475 };
8476 static const struct message WmWinEventAlertSeq[] = {
8477 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
8478 { 0 }
8479 };
8480 static const struct message WmWinEventAlertSeq_2[] = {
8481 /* create window in the thread proc */
8482 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
8483 /* our test event */
8484 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
8485 { 0 }
8486 };
8487 static const struct message WmGlobalHookSeq_1[] = {
8488 /* create window in the thread proc */
8489 { HCBT_CREATEWND, hook|lparam, 0, 2 },
8490 /* our test events */
8491 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
8492 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
8493 { 0 }
8494 };
8495 static const struct message WmGlobalHookSeq_2[] = {
8496 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
8497 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
8498 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
8499 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
8500 { 0 }
8501 };
8502
8503 static const struct message WmMouseLLHookSeq[] = {
8504 { WM_MOUSEMOVE, hook },
8505 { WM_LBUTTONUP, hook },
8506 { WM_MOUSEMOVE, hook },
8507 { 0 }
8508 };
8509
8510 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
8511 DWORD event,
8512 HWND hwnd,
8513 LONG object_id,
8514 LONG child_id,
8515 DWORD thread_id,
8516 DWORD event_time)
8517 {
8518 char buf[256];
8519
8520 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8521 {
8522 if (!lstrcmpiA(buf, "TestWindowClass") ||
8523 !lstrcmpiA(buf, "static"))
8524 {
8525 struct recvd_message msg;
8526
8527 msg.hwnd = hwnd;
8528 msg.message = event;
8529 msg.flags = winevent_hook|wparam|lparam;
8530 msg.wParam = object_id;
8531 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8532 msg.descr = "WEH_2";
8533 add_message(&msg);
8534 }
8535 }
8536 }
8537
8538 static HHOOK hCBT_global_hook;
8539 static DWORD cbt_global_hook_thread_id;
8540
8541 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
8542 {
8543 HWND hwnd;
8544 char buf[256];
8545
8546 if (nCode == HCBT_SYSCOMMAND)
8547 {
8548 struct recvd_message msg;
8549
8550 msg.hwnd = 0;
8551 msg.message = nCode;
8552 msg.flags = hook|wparam|lparam;
8553 msg.wParam = wParam;
8554 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8555 msg.descr = "CBT_2";
8556 add_message(&msg);
8557
8558 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8559 }
8560 /* WH_MOUSE_LL hook */
8561 if (nCode == HC_ACTION)
8562 {
8563 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8564
8565 /* we can't test for real mouse events */
8566 if (mhll->flags & LLMHF_INJECTED)
8567 {
8568 struct recvd_message msg;
8569
8570 memset (&msg, 0, sizeof (msg));
8571 msg.message = wParam;
8572 msg.flags = hook;
8573 msg.descr = "CBT_2";
8574 add_message(&msg);
8575 }
8576 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8577 }
8578
8579 /* Log also SetFocus(0) calls */
8580 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8581
8582 if (GetClassNameA(hwnd, buf, sizeof(buf)))
8583 {
8584 if (!lstrcmpiA(buf, "TestWindowClass") ||
8585 !lstrcmpiA(buf, "static"))
8586 {
8587 struct recvd_message msg;
8588
8589 msg.hwnd = hwnd;
8590 msg.message = nCode;
8591 msg.flags = hook|wparam|lparam;
8592 msg.wParam = wParam;
8593 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8594 msg.descr = "CBT_2";
8595 add_message(&msg);
8596 }
8597 }
8598 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8599 }
8600
8601 static DWORD WINAPI win_event_global_thread_proc(void *param)
8602 {
8603 HWND hwnd;
8604 MSG msg;
8605 HANDLE hevent = *(HANDLE *)param;
8606
8607 assert(pNotifyWinEvent);
8608
8609 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8610 assert(hwnd);
8611 trace("created thread window %p\n", hwnd);
8612
8613 *(HWND *)param = hwnd;
8614
8615 flush_sequence();
8616 /* this event should be received only by our new hook proc,
8617 * an old one does not expect an event from another thread.
8618 */
8619 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8620 SetEvent(hevent);
8621
8622 while (GetMessageA(&msg, 0, 0, 0))
8623 {
8624 TranslateMessage(&msg);
8625 DispatchMessageA(&msg);
8626 }
8627 return 0;
8628 }
8629
8630 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8631 {
8632 HWND hwnd;
8633 MSG msg;
8634 HANDLE hevent = *(HANDLE *)param;
8635
8636 flush_sequence();
8637 /* these events should be received only by our new hook proc,
8638 * an old one does not expect an event from another thread.
8639 */
8640
8641 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8642 assert(hwnd);
8643 trace("created thread window %p\n", hwnd);
8644
8645 *(HWND *)param = hwnd;
8646
8647 /* Windows doesn't like when a thread plays games with the focus,
8648 that leads to all kinds of misbehaviours and failures to activate
8649 a window. So, better keep next lines commented out.
8650 SetFocus(0);
8651 SetFocus(hwnd);*/
8652
8653 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8654 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8655
8656 SetEvent(hevent);
8657
8658 while (GetMessageA(&msg, 0, 0, 0))
8659 {
8660 TranslateMessage(&msg);
8661 DispatchMessageA(&msg);
8662 }
8663 return 0;
8664 }
8665
8666 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8667 {
8668 HWND hwnd;
8669 MSG msg;
8670 HANDLE hevent = *(HANDLE *)param;
8671
8672 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8673 assert(hwnd);
8674 trace("created thread window %p\n", hwnd);
8675
8676 *(HWND *)param = hwnd;
8677
8678 flush_sequence();
8679
8680 /* Windows doesn't like when a thread plays games with the focus,
8681 * that leads to all kinds of misbehaviours and failures to activate
8682 * a window. So, better don't generate a mouse click message below.
8683 */
8684 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8685 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8686 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8687
8688 SetEvent(hevent);
8689 while (GetMessageA(&msg, 0, 0, 0))
8690 {
8691 TranslateMessage(&msg);
8692 DispatchMessageA(&msg);
8693 }
8694 return 0;
8695 }
8696
8697 static void test_winevents(void)
8698 {
8699 BOOL ret;
8700 MSG msg;
8701 HWND hwnd, hwnd2;
8702 UINT i;
8703 HANDLE hthread, hevent;
8704 DWORD tid;
8705 HWINEVENTHOOK hhook;
8706 const struct message *events = WmWinEventsSeq;
8707
8708 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8709 WS_OVERLAPPEDWINDOW,
8710 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8711 NULL, NULL, 0);
8712 assert(hwnd);
8713
8714 /****** start of global hook test *************/
8715 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8716 if (!hCBT_global_hook)
8717 {
8718 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8719 skip( "cannot set global hook\n" );
8720 return;
8721 }
8722
8723 hevent = CreateEventA(NULL, 0, 0, NULL);
8724 assert(hevent);
8725 hwnd2 = hevent;
8726
8727 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8728 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8729
8730 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8731
8732 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8733
8734 flush_sequence();
8735 /* this one should be received only by old hook proc */
8736 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8737 /* this one should be received only by old hook proc */
8738 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8739
8740 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8741
8742 ret = UnhookWindowsHookEx(hCBT_global_hook);
8743 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8744
8745 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8746 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8747 CloseHandle(hthread);
8748 CloseHandle(hevent);
8749 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8750 /****** end of global hook test *************/
8751
8752 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8753 {
8754 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8755 return;
8756 }
8757
8758 flush_sequence();
8759
8760 if (0)
8761 {
8762 /* this test doesn't pass under Win9x */
8763 /* win2k ignores events with hwnd == 0 */
8764 SetLastError(0xdeadbeef);
8765 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8766 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8767 GetLastError() == 0xdeadbeef, /* Win9x */
8768 "unexpected error %d\n", GetLastError());
8769 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8770 }
8771
8772 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8773 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8774
8775 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8776
8777 /****** start of event filtering test *************/
8778 hhook = pSetWinEventHook(
8779 EVENT_OBJECT_SHOW, /* 0x8002 */
8780 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8781 GetModuleHandleA(0), win_event_global_hook_proc,
8782 GetCurrentProcessId(), 0,
8783 WINEVENT_INCONTEXT);
8784 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8785
8786 hevent = CreateEventA(NULL, 0, 0, NULL);
8787 assert(hevent);
8788 hwnd2 = hevent;
8789
8790 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8791 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8792
8793 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8794
8795 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8796
8797 flush_sequence();
8798 /* this one should be received only by old hook proc */
8799 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8800 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8801 /* this one should be received only by old hook proc */
8802 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8803
8804 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8805
8806 ret = pUnhookWinEvent(hhook);
8807 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8808
8809 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8810 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8811 CloseHandle(hthread);
8812 CloseHandle(hevent);
8813 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8814 /****** end of event filtering test *************/
8815
8816 /****** start of out of context event test *************/
8817 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8818 win_event_global_hook_proc, GetCurrentProcessId(), 0,
8819 WINEVENT_OUTOFCONTEXT);
8820 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8821
8822 hevent = CreateEventA(NULL, 0, 0, NULL);
8823 assert(hevent);
8824 hwnd2 = hevent;
8825
8826 flush_sequence();
8827
8828 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8829 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8830
8831 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8832
8833 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8834 /* process pending winevent messages */
8835 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8836 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8837
8838 flush_sequence();
8839 /* this one should be received only by old hook proc */
8840 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8841 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8842 /* this one should be received only by old hook proc */
8843 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8844
8845 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8846 /* process pending winevent messages */
8847 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8848 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8849
8850 ret = pUnhookWinEvent(hhook);
8851 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8852
8853 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8854 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8855 CloseHandle(hthread);
8856 CloseHandle(hevent);
8857 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8858 /****** end of out of context event test *************/
8859
8860 /****** start of MOUSE_LL hook test *************/
8861 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8862 /* WH_MOUSE_LL is not supported on Win9x platforms */
8863 if (!hCBT_global_hook)
8864 {
8865 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8866 goto skip_mouse_ll_hook_test;
8867 }
8868
8869 hevent = CreateEventA(NULL, 0, 0, NULL);
8870 assert(hevent);
8871 hwnd2 = hevent;
8872
8873 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8874 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8875
8876 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8877 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8878
8879 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8880 flush_sequence();
8881
8882 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8883 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8884 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8885
8886 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8887
8888 ret = UnhookWindowsHookEx(hCBT_global_hook);
8889 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8890
8891 PostThreadMessageA(tid, WM_QUIT, 0, 0);
8892 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8893 CloseHandle(hthread);
8894 CloseHandle(hevent);
8895 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8896 /****** end of MOUSE_LL hook test *************/
8897 skip_mouse_ll_hook_test:
8898
8899 ok(DestroyWindow(hwnd), "failed to destroy window\n");
8900 }
8901
8902 static void test_set_hook(void)
8903 {
8904 BOOL ret;
8905 HHOOK hhook;
8906 HWINEVENTHOOK hwinevent_hook;
8907
8908 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8909 ok(hhook != 0, "local hook does not require hModule set to 0\n");
8910 UnhookWindowsHookEx(hhook);
8911
8912 if (0)
8913 {
8914 /* this test doesn't pass under Win9x: BUG! */
8915 SetLastError(0xdeadbeef);
8916 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8917 ok(!hhook, "global hook requires hModule != 0\n");
8918 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8919 }
8920
8921 SetLastError(0xdeadbeef);
8922 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8923 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8924 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8925 GetLastError() == 0xdeadbeef, /* Win9x */
8926 "unexpected error %d\n", GetLastError());
8927
8928 SetLastError(0xdeadbeef);
8929 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8930 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8931 GetLastError() == 0xdeadbeef, /* Win9x */
8932 "unexpected error %d\n", GetLastError());
8933
8934 if (!pSetWinEventHook || !pUnhookWinEvent) return;
8935
8936 /* even process local incontext hooks require hmodule */
8937 SetLastError(0xdeadbeef);
8938 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8939 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8940 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8941 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8942 GetLastError() == 0xdeadbeef, /* Win9x */
8943 "unexpected error %d\n", GetLastError());
8944
8945 /* even thread local incontext hooks require hmodule */
8946 SetLastError(0xdeadbeef);
8947 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8948 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8949 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8950 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8951 GetLastError() == 0xdeadbeef, /* Win9x */
8952 "unexpected error %d\n", GetLastError());
8953
8954 if (0)
8955 {
8956 /* these 3 tests don't pass under Win9x */
8957 SetLastError(0xdeadbeef);
8958 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8959 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8960 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8961 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8962
8963 SetLastError(0xdeadbeef);
8964 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8965 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8966 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8967 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8968
8969 SetLastError(0xdeadbeef);
8970 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8971 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8972 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8973 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8974 }
8975
8976 SetLastError(0xdeadbeef);
8977 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8978 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8979 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8980 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8981 ret = pUnhookWinEvent(hwinevent_hook);
8982 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8983
8984 todo_wine {
8985 /* This call succeeds under win2k SP4, but fails under Wine.
8986 Does win2k test/use passed process id? */
8987 SetLastError(0xdeadbeef);
8988 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8989 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8990 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8991 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8992 ret = pUnhookWinEvent(hwinevent_hook);
8993 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8994 }
8995
8996 SetLastError(0xdeadbeef);
8997 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8998 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8999 GetLastError() == 0xdeadbeef, /* Win9x */
9000 "unexpected error %d\n", GetLastError());
9001 }
9002
9003 static const struct message ScrollWindowPaint1[] = {
9004 { WM_PAINT, sent },
9005 { WM_ERASEBKGND, sent|beginpaint },
9006 { WM_GETTEXTLENGTH, sent|optional },
9007 { WM_PAINT, sent|optional },
9008 { WM_NCPAINT, sent|beginpaint|optional },
9009 { WM_GETTEXT, sent|beginpaint|optional },
9010 { WM_GETTEXT, sent|beginpaint|optional },
9011 { WM_GETTEXT, sent|beginpaint|optional },
9012 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
9013 { WM_ERASEBKGND, sent|beginpaint|optional },
9014 { 0 }
9015 };
9016
9017 static const struct message ScrollWindowPaint2[] = {
9018 { WM_PAINT, sent },
9019 { 0 }
9020 };
9021
9022 static void test_scrollwindowex(void)
9023 {
9024 HWND hwnd, hchild;
9025 RECT rect={0,0,130,130};
9026
9027 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
9028 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
9029 100, 100, 200, 200, 0, 0, 0, NULL);
9030 ok (hwnd != 0, "Failed to create overlapped window\n");
9031 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
9032 WS_VISIBLE|WS_CAPTION|WS_CHILD,
9033 10, 10, 150, 150, hwnd, 0, 0, NULL);
9034 ok (hchild != 0, "Failed to create child\n");
9035 UpdateWindow(hwnd);
9036 flush_events();
9037 flush_sequence();
9038
9039 /* scroll without the child window */
9040 trace("start scroll\n");
9041 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
9042 SW_ERASE|SW_INVALIDATE);
9043 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
9044 trace("end scroll\n");
9045 flush_sequence();
9046 flush_events();
9047 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
9048 flush_events();
9049 flush_sequence();
9050
9051 /* Now without the SW_ERASE flag */
9052 trace("start scroll\n");
9053 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
9054 ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
9055 trace("end scroll\n");
9056 flush_sequence();
9057 flush_events();
9058 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
9059 flush_events();
9060 flush_sequence();
9061
9062 /* now scroll the child window as well */
9063 trace("start scroll\n");
9064 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
9065 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
9066 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
9067 /* windows sometimes a WM_MOVE */
9068 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
9069 trace("end scroll\n");
9070 flush_sequence();
9071 flush_events();
9072 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
9073 flush_events();
9074 flush_sequence();
9075
9076 /* now scroll with ScrollWindow() */
9077 trace("start scroll with ScrollWindow\n");
9078 ScrollWindow( hwnd, 5, 5, NULL, NULL);
9079 trace("end scroll\n");
9080 flush_sequence();
9081 flush_events();
9082 ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
9083
9084 ok(DestroyWindow(hchild), "failed to destroy window\n");
9085 ok(DestroyWindow(hwnd), "failed to destroy window\n");
9086 flush_sequence();
9087 }
9088
9089 static const struct message destroy_window_with_children[] = {
9090 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
9091 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
9092 { 0x0090, sent|optional },
9093 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
9094 { 0x0090, sent|optional },
9095 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
9096 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9097 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9098 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
9099 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
9100 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
9101 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
9102 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
9103 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
9104 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
9105 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
9106 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
9107 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
9108 { 0 }
9109 };
9110
9111 static void test_DestroyWindow(void)
9112 {
9113 BOOL ret;
9114 HWND parent, child1, child2, child3, child4, test;
9115 UINT_PTR child_id = WND_CHILD_ID + 1;
9116
9117 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9118 100, 100, 200, 200, 0, 0, 0, NULL);
9119 assert(parent != 0);
9120 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9121 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
9122 assert(child1 != 0);
9123 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9124 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
9125 assert(child2 != 0);
9126 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
9127 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
9128 assert(child3 != 0);
9129 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
9130 0, 0, 50, 50, parent, 0, 0, NULL);
9131 assert(child4 != 0);
9132
9133 /* test owner/parent of child2 */
9134 test = GetParent(child2);
9135 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9136 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
9137 if(pGetAncestor) {
9138 test = pGetAncestor(child2, GA_PARENT);
9139 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9140 }
9141 test = GetWindow(child2, GW_OWNER);
9142 ok(!test, "wrong owner %p\n", test);
9143
9144 test = SetParent(child2, parent);
9145 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
9146
9147 /* test owner/parent of the parent */
9148 test = GetParent(parent);
9149 ok(!test, "wrong parent %p\n", test);
9150 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
9151 if(pGetAncestor) {
9152 test = pGetAncestor(parent, GA_PARENT);
9153 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9154 }
9155 test = GetWindow(parent, GW_OWNER);
9156 ok(!test, "wrong owner %p\n", test);
9157
9158 /* test owner/parent of child1 */
9159 test = GetParent(child1);
9160 ok(test == parent, "wrong parent %p\n", test);
9161 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
9162 if(pGetAncestor) {
9163 test = pGetAncestor(child1, GA_PARENT);
9164 ok(test == parent, "wrong parent %p\n", test);
9165 }
9166 test = GetWindow(child1, GW_OWNER);
9167 ok(!test, "wrong owner %p\n", test);
9168
9169 /* test owner/parent of child2 */
9170 test = GetParent(child2);
9171 ok(test == parent, "wrong parent %p\n", test);
9172 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
9173 if(pGetAncestor) {
9174 test = pGetAncestor(child2, GA_PARENT);
9175 ok(test == parent, "wrong parent %p\n", test);
9176 }
9177 test = GetWindow(child2, GW_OWNER);
9178 ok(!test, "wrong owner %p\n", test);
9179
9180 /* test owner/parent of child3 */
9181 test = GetParent(child3);
9182 ok(test == child1, "wrong parent %p\n", test);
9183 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
9184 if(pGetAncestor) {
9185 test = pGetAncestor(child3, GA_PARENT);
9186 ok(test == child1, "wrong parent %p\n", test);
9187 }
9188 test = GetWindow(child3, GW_OWNER);
9189 ok(!test, "wrong owner %p\n", test);
9190
9191 /* test owner/parent of child4 */
9192 test = GetParent(child4);
9193 ok(test == parent, "wrong parent %p\n", test);
9194 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
9195 if(pGetAncestor) {
9196 test = pGetAncestor(child4, GA_PARENT);
9197 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
9198 }
9199 test = GetWindow(child4, GW_OWNER);
9200 ok(test == parent, "wrong owner %p\n", test);
9201
9202 flush_sequence();
9203
9204 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
9205 parent, child1, child2, child3, child4);
9206
9207 SetCapture(child4);
9208 test = GetCapture();
9209 ok(test == child4, "wrong capture window %p\n", test);
9210
9211 test_DestroyWindow_flag = TRUE;
9212 ret = DestroyWindow(parent);
9213 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9214 test_DestroyWindow_flag = FALSE;
9215 ok_sequence(destroy_window_with_children, "destroy window with children", 0);
9216
9217 ok(!IsWindow(parent), "parent still exists\n");
9218 ok(!IsWindow(child1), "child1 still exists\n");
9219 ok(!IsWindow(child2), "child2 still exists\n");
9220 ok(!IsWindow(child3), "child3 still exists\n");
9221 ok(!IsWindow(child4), "child4 still exists\n");
9222
9223 test = GetCapture();
9224 ok(!test, "wrong capture window %p\n", test);
9225 }
9226
9227
9228 static const struct message WmDispatchPaint[] = {
9229 { WM_NCPAINT, sent },
9230 { WM_GETTEXT, sent|defwinproc|optional },
9231 { WM_GETTEXT, sent|defwinproc|optional },
9232 { WM_ERASEBKGND, sent },
9233 { 0 }
9234 };
9235
9236 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9237 {
9238 if (message == WM_PAINT) return 0;
9239 return MsgCheckProcA( hwnd, message, wParam, lParam );
9240 }
9241
9242 static void test_DispatchMessage(void)
9243 {
9244 RECT rect;
9245 MSG msg;
9246 int count;
9247 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9248 100, 100, 200, 200, 0, 0, 0, NULL);
9249 ShowWindow( hwnd, SW_SHOW );
9250 UpdateWindow( hwnd );
9251 flush_events();
9252 flush_sequence();
9253 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
9254
9255 SetRect( &rect, -5, -5, 5, 5 );
9256 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9257 count = 0;
9258 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9259 {
9260 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9261 else
9262 {
9263 flush_sequence();
9264 DispatchMessageA( &msg );
9265 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
9266 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9267 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
9268 if (++count > 10) break;
9269 }
9270 }
9271 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
9272
9273 trace("now without DispatchMessage\n");
9274 flush_sequence();
9275 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9276 count = 0;
9277 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9278 {
9279 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9280 else
9281 {
9282 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
9283 flush_sequence();
9284 /* this will send WM_NCCPAINT just like DispatchMessage does */
9285 GetUpdateRgn( hwnd, hrgn, TRUE );
9286 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9287 DeleteObject( hrgn );
9288 GetClientRect( hwnd, &rect );
9289 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
9290 ok( !count, "Got multiple WM_PAINTs\n" );
9291 if (++count > 10) break;
9292 }
9293 }
9294
9295 flush_sequence();
9296 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9297 count = 0;
9298 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9299 {
9300 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
9301 else
9302 {
9303 HDC hdc;
9304
9305 flush_sequence();
9306 hdc = BeginPaint( hwnd, NULL );
9307 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
9308 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
9309 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9310 ok( !count, "Got multiple WM_PAINTs\n" );
9311 if (++count > 10) break;
9312 }
9313 }
9314 DestroyWindow(hwnd);
9315 }
9316
9317
9318 static const struct message WmUser[] = {
9319 { WM_USER, sent },
9320 { 0 }
9321 };
9322
9323 struct sendmsg_info
9324 {
9325 HWND hwnd;
9326 DWORD timeout;
9327 DWORD ret;
9328 };
9329
9330 static DWORD CALLBACK send_msg_thread( LPVOID arg )
9331 {
9332 struct sendmsg_info *info = arg;
9333 SetLastError( 0xdeadbeef );
9334 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
9335 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
9336 broken(GetLastError() == 0), /* win9x */
9337 "unexpected error %d\n", GetLastError());
9338 return 0;
9339 }
9340
9341 static void wait_for_thread( HANDLE thread )
9342 {
9343 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
9344 {
9345 MSG msg;
9346 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
9347 }
9348 }
9349
9350 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9351 {
9352 if (message == WM_USER) Sleep(200);
9353 return MsgCheckProcA( hwnd, message, wParam, lParam );
9354 }
9355
9356 static void test_SendMessageTimeout(void)
9357 {
9358 HANDLE thread;
9359 struct sendmsg_info info;
9360 DWORD tid;
9361 BOOL is_win9x;
9362
9363 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9364 100, 100, 200, 200, 0, 0, 0, NULL);
9365 flush_events();
9366 flush_sequence();
9367
9368 info.timeout = 1000;
9369 info.ret = 0xdeadbeef;
9370 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9371 wait_for_thread( thread );
9372 CloseHandle( thread );
9373 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9374 ok_sequence( WmUser, "WmUser", FALSE );
9375
9376 info.timeout = 1;
9377 info.ret = 0xdeadbeef;
9378 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9379 Sleep(100); /* SendMessageTimeout should time out here */
9380 wait_for_thread( thread );
9381 CloseHandle( thread );
9382 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9383 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9384
9385 /* 0 means infinite timeout (but not on win9x) */
9386 info.timeout = 0;
9387 info.ret = 0xdeadbeef;
9388 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9389 Sleep(100);
9390 wait_for_thread( thread );
9391 CloseHandle( thread );
9392 is_win9x = !info.ret;
9393 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9394 else ok_sequence( WmUser, "WmUser", FALSE );
9395
9396 /* timeout is treated as signed despite the prototype (but not on win9x) */
9397 info.timeout = 0x7fffffff;
9398 info.ret = 0xdeadbeef;
9399 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9400 Sleep(100);
9401 wait_for_thread( thread );
9402 CloseHandle( thread );
9403 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9404 ok_sequence( WmUser, "WmUser", FALSE );
9405
9406 info.timeout = 0x80000000;
9407 info.ret = 0xdeadbeef;
9408 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9409 Sleep(100);
9410 wait_for_thread( thread );
9411 CloseHandle( thread );
9412 if (is_win9x)
9413 {
9414 ok( info.ret == 1, "SendMessageTimeout failed\n" );
9415 ok_sequence( WmUser, "WmUser", FALSE );
9416 }
9417 else
9418 {
9419 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9420 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9421 }
9422
9423 /* now check for timeout during message processing */
9424 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
9425 info.timeout = 100;
9426 info.ret = 0xdeadbeef;
9427 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9428 wait_for_thread( thread );
9429 CloseHandle( thread );
9430 /* we should time out but still get the message */
9431 ok( info.ret == 0, "SendMessageTimeout failed\n" );
9432 ok_sequence( WmUser, "WmUser", FALSE );
9433
9434 DestroyWindow( info.hwnd );
9435 }
9436
9437
9438 /****************** edit message test *************************/
9439 #define ID_EDIT 0x1234
9440 static const struct message sl_edit_setfocus[] =
9441 {
9442 { HCBT_SETFOCUS, hook },
9443 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9444 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9445 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9446 { WM_SETFOCUS, sent|wparam, 0 },
9447 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9448 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
9449 { WM_CTLCOLOREDIT, sent|parent },
9450 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9451 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9452 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9453 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9454 { 0 }
9455 };
9456 static const struct message sl_edit_invisible[] =
9457 {
9458 { HCBT_SETFOCUS, hook },
9459 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9460 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9461 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9462 { WM_KILLFOCUS, sent|parent },
9463 { WM_SETFOCUS, sent },
9464 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9465 { 0 }
9466 };
9467 static const struct message ml_edit_setfocus[] =
9468 {
9469 { HCBT_SETFOCUS, hook },
9470 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9471 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9472 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9473 { WM_SETFOCUS, sent|wparam, 0 },
9474 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9475 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9476 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9477 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9478 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9479 { 0 }
9480 };
9481 static const struct message sl_edit_killfocus[] =
9482 {
9483 { HCBT_SETFOCUS, hook },
9484 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9485 { WM_KILLFOCUS, sent|wparam, 0 },
9486 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9487 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9488 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
9489 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9490 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
9491 { 0 }
9492 };
9493 static const struct message sl_edit_lbutton_dblclk[] =
9494 {
9495 { WM_LBUTTONDBLCLK, sent },
9496 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9497 { 0 }
9498 };
9499 static const struct message sl_edit_lbutton_down[] =
9500 {
9501 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9502 { HCBT_SETFOCUS, hook },
9503 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9504 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9505 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9506 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9507 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9508 { WM_CTLCOLOREDIT, sent|parent },
9509 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9510 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9511 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9512 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9513 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9514 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9515 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9516 { WM_CTLCOLOREDIT, sent|parent|optional },
9517 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9518 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9519 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9520 { 0 }
9521 };
9522 static const struct message ml_edit_lbutton_down[] =
9523 {
9524 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9525 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9526 { HCBT_SETFOCUS, hook },
9527 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9528 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9529 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9530 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9531 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9532 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9533 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9534 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9535 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9536 { 0 }
9537 };
9538 static const struct message sl_edit_lbutton_up[] =
9539 {
9540 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9541 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9542 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9543 { WM_CAPTURECHANGED, sent|defwinproc },
9544 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9545 { 0 }
9546 };
9547 static const struct message ml_edit_lbutton_up[] =
9548 {
9549 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9550 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9551 { WM_CAPTURECHANGED, sent|defwinproc },
9552 { 0 }
9553 };
9554
9555 static WNDPROC old_edit_proc;
9556
9557 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9558 {
9559 static LONG defwndproc_counter = 0;
9560 LRESULT ret;
9561 struct recvd_message msg;
9562
9563 if (ignore_message( message )) return 0;
9564
9565 msg.hwnd = hwnd;
9566 msg.message = message;
9567 msg.flags = sent|wparam|lparam;
9568 if (defwndproc_counter) msg.flags |= defwinproc;
9569 msg.wParam = wParam;
9570 msg.lParam = lParam;
9571 msg.descr = "edit";
9572 add_message(&msg);
9573
9574 defwndproc_counter++;
9575 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9576 defwndproc_counter--;
9577
9578 return ret;
9579 }
9580
9581 static void subclass_edit(void)
9582 {
9583 WNDCLASSA cls;
9584
9585 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9586
9587 old_edit_proc = cls.lpfnWndProc;
9588
9589 cls.hInstance = GetModuleHandleA(NULL);
9590 cls.lpfnWndProc = edit_hook_proc;
9591 cls.lpszClassName = "my_edit_class";
9592 UnregisterClassA(cls.lpszClassName, cls.hInstance);
9593 if (!RegisterClassA(&cls)) assert(0);
9594 }
9595
9596 static void test_edit_messages(void)
9597 {
9598 HWND hwnd, parent;
9599 DWORD dlg_code;
9600
9601 subclass_edit();
9602 log_all_parent_messages++;
9603
9604 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9605 100, 100, 200, 200, 0, 0, 0, NULL);
9606 ok (parent != 0, "Failed to create parent window\n");
9607
9608 /* test single line edit */
9609 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9610 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9611 ok(hwnd != 0, "Failed to create edit window\n");
9612
9613 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9614 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9615
9616 flush_sequence();
9617 SetFocus(hwnd);
9618 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
9619
9620 ShowWindow(hwnd, SW_SHOW);
9621 UpdateWindow(hwnd);
9622 SetFocus(0);
9623 flush_sequence();
9624
9625 SetFocus(hwnd);
9626 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9627
9628 SetFocus(0);
9629 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9630
9631 SetFocus(0);
9632 ReleaseCapture();
9633 flush_sequence();
9634
9635 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9636 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9637
9638 SetFocus(0);
9639 ReleaseCapture();
9640 flush_sequence();
9641
9642 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9643 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9644
9645 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9646 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9647
9648 DestroyWindow(hwnd);
9649
9650 /* test multiline edit */
9651 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9652 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9653 ok(hwnd != 0, "Failed to create edit window\n");
9654
9655 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9656 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9657 "wrong dlg_code %08x\n", dlg_code);
9658
9659 ShowWindow(hwnd, SW_SHOW);
9660 UpdateWindow(hwnd);
9661 SetFocus(0);
9662 flush_sequence();
9663
9664 SetFocus(hwnd);
9665 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9666
9667 SetFocus(0);
9668 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9669
9670 SetFocus(0);
9671 ReleaseCapture();
9672 flush_sequence();
9673
9674 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9675 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9676
9677 SetFocus(0);
9678 ReleaseCapture();
9679 flush_sequence();
9680
9681 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9682 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9683
9684 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9685 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9686
9687 DestroyWindow(hwnd);
9688 DestroyWindow(parent);
9689
9690 log_all_parent_messages--;
9691 }
9692
9693 /**************************** End of Edit test ******************************/
9694
9695 static const struct message WmKeyDownSkippedSeq[] =
9696 {
9697 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9698 { 0 }
9699 };
9700 static const struct message WmKeyDownWasDownSkippedSeq[] =
9701 {
9702 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9703 { 0 }
9704 };
9705 static const struct message WmKeyUpSkippedSeq[] =
9706 {
9707 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9708 { 0 }
9709 };
9710 static const struct message WmUserKeyUpSkippedSeq[] =
9711 {
9712 { WM_USER, sent },
9713 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9714 { 0 }
9715 };
9716
9717 #define EV_STOP 0
9718 #define EV_SENDMSG 1
9719 #define EV_ACK 2
9720
9721 struct peekmsg_info
9722 {
9723 HWND hwnd;
9724 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9725 };
9726
9727 static DWORD CALLBACK send_msg_thread_2(void *param)
9728 {
9729 DWORD ret;
9730 struct peekmsg_info *info = param;
9731
9732 trace("thread: looping\n");
9733 SetEvent(info->hevent[EV_ACK]);
9734
9735 while (1)
9736 {
9737 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9738
9739 switch (ret)
9740 {
9741 case WAIT_OBJECT_0 + EV_STOP:
9742 trace("thread: exiting\n");
9743 return 0;
9744
9745 case WAIT_OBJECT_0 + EV_SENDMSG:
9746 trace("thread: sending message\n");
9747 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
9748 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
9749 SetEvent(info->hevent[EV_ACK]);
9750 break;
9751
9752 default:
9753 trace("unexpected return: %04x\n", ret);
9754 assert(0);
9755 break;
9756 }
9757 }
9758 return 0;
9759 }
9760
9761 static void test_PeekMessage(void)
9762 {
9763 MSG msg;
9764 HANDLE hthread;
9765 DWORD tid, qstatus;
9766 UINT qs_all_input = QS_ALLINPUT;
9767 UINT qs_input = QS_INPUT;
9768 BOOL ret;
9769 struct peekmsg_info info;
9770
9771 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9772 100, 100, 200, 200, 0, 0, 0, NULL);
9773 assert(info.hwnd);
9774 ShowWindow(info.hwnd, SW_SHOW);
9775 UpdateWindow(info.hwnd);
9776 SetFocus(info.hwnd);
9777
9778 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9779 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9780 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9781
9782 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9783 WaitForSingleObject(info.hevent[EV_ACK], 10000);
9784
9785 flush_events();
9786 flush_sequence();
9787
9788 SetLastError(0xdeadbeef);
9789 qstatus = GetQueueStatus(qs_all_input);
9790 if (GetLastError() == ERROR_INVALID_FLAGS)
9791 {
9792 trace("QS_RAWINPUT not supported on this platform\n");
9793 qs_all_input &= ~QS_RAWINPUT;
9794 qs_input &= ~QS_RAWINPUT;
9795 }
9796 if (qstatus & QS_POSTMESSAGE)
9797 {
9798 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9799 qstatus = GetQueueStatus(qs_all_input);
9800 }
9801 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9802
9803 trace("signalling to send message\n");
9804 SetEvent(info.hevent[EV_SENDMSG]);
9805 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9806
9807 /* pass invalid QS_xxxx flags */
9808 SetLastError(0xdeadbeef);
9809 qstatus = GetQueueStatus(0xffffffff);
9810 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9811 if (!qstatus)
9812 {
9813 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9814 qstatus = GetQueueStatus(qs_all_input);
9815 }
9816 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
9817 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9818 "wrong qstatus %08x\n", qstatus);
9819
9820 msg.message = 0;
9821 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9822 ok(!ret,
9823 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9824 msg.message);
9825 ok_sequence(WmUser, "WmUser", FALSE);
9826
9827 qstatus = GetQueueStatus(qs_all_input);
9828 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9829
9830 keybd_event('N', 0, 0, 0);
9831 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9832 qstatus = GetQueueStatus(qs_all_input);
9833 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9834 {
9835 skip( "queuing key events not supported\n" );
9836 goto done;
9837 }
9838 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
9839 /* keybd_event seems to trigger a sent message on NT4 */
9840 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
9841 "wrong qstatus %08x\n", qstatus);
9842
9843 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9844 qstatus = GetQueueStatus(qs_all_input);
9845 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
9846 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9847 "wrong qstatus %08x\n", qstatus);
9848
9849 InvalidateRect(info.hwnd, NULL, FALSE);
9850 qstatus = GetQueueStatus(qs_all_input);
9851 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
9852 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9853 "wrong qstatus %08x\n", qstatus);
9854
9855 trace("signalling to send message\n");
9856 SetEvent(info.hevent[EV_SENDMSG]);
9857 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9858
9859 qstatus = GetQueueStatus(qs_all_input);
9860 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9861 "wrong qstatus %08x\n", qstatus);
9862
9863 msg.message = 0;
9864 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9865 if (ret && msg.message == WM_CHAR)
9866 {
9867 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9868 goto done;
9869 }
9870 ok(!ret,
9871 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9872 msg.message);
9873 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
9874 {
9875 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9876 goto done;
9877 }
9878 ok_sequence(WmUser, "WmUser", FALSE);
9879
9880 qstatus = GetQueueStatus(qs_all_input);
9881 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9882 "wrong qstatus %08x\n", qstatus);
9883
9884 trace("signalling to send message\n");
9885 SetEvent(info.hevent[EV_SENDMSG]);
9886 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9887
9888 qstatus = GetQueueStatus(qs_all_input);
9889 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9890 "wrong qstatus %08x\n", qstatus);
9891
9892 msg.message = 0;
9893 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9894 ok(!ret,
9895 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9896 msg.message);
9897 ok_sequence(WmUser, "WmUser", FALSE);
9898
9899 qstatus = GetQueueStatus(qs_all_input);
9900 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9901 "wrong qstatus %08x\n", qstatus);
9902
9903 msg.message = 0;
9904 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9905 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9906 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9907 ret, msg.message, msg.wParam);
9908 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9909
9910 qstatus = GetQueueStatus(qs_all_input);
9911 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9912 "wrong qstatus %08x\n", qstatus);
9913
9914 msg.message = 0;
9915 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9916 ok(!ret,
9917 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9918 msg.message);
9919 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9920
9921 qstatus = GetQueueStatus(qs_all_input);
9922 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9923 "wrong qstatus %08x\n", qstatus);
9924
9925 msg.message = 0;
9926 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9927 ok(ret && msg.message == WM_PAINT,
9928 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9929 DispatchMessageA(&msg);
9930 ok_sequence(WmPaint, "WmPaint", FALSE);
9931
9932 qstatus = GetQueueStatus(qs_all_input);
9933 ok(qstatus == MAKELONG(0, QS_KEY),
9934 "wrong qstatus %08x\n", qstatus);
9935
9936 msg.message = 0;
9937 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9938 ok(!ret,
9939 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9940 msg.message);
9941 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9942
9943 qstatus = GetQueueStatus(qs_all_input);
9944 ok(qstatus == MAKELONG(0, QS_KEY),
9945 "wrong qstatus %08x\n", qstatus);
9946
9947 trace("signalling to send message\n");
9948 SetEvent(info.hevent[EV_SENDMSG]);
9949 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9950
9951 qstatus = GetQueueStatus(qs_all_input);
9952 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9953 "wrong qstatus %08x\n", qstatus);
9954
9955 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9956
9957 qstatus = GetQueueStatus(qs_all_input);
9958 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9959 "wrong qstatus %08x\n", qstatus);
9960
9961 msg.message = 0;
9962 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9963 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9964 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9965 ret, msg.message, msg.wParam);
9966 ok_sequence(WmUser, "WmUser", FALSE);
9967
9968 qstatus = GetQueueStatus(qs_all_input);
9969 ok(qstatus == MAKELONG(0, QS_KEY),
9970 "wrong qstatus %08x\n", qstatus);
9971
9972 msg.message = 0;
9973 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9974 ok(!ret,
9975 "PeekMessageA should have returned FALSE instead of msg %04x\n",
9976 msg.message);
9977 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9978
9979 qstatus = GetQueueStatus(qs_all_input);
9980 ok(qstatus == MAKELONG(0, QS_KEY),
9981 "wrong qstatus %08x\n", qstatus);
9982
9983 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9984
9985 qstatus = GetQueueStatus(qs_all_input);
9986 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9987 "wrong qstatus %08x\n", qstatus);
9988
9989 trace("signalling to send message\n");
9990 SetEvent(info.hevent[EV_SENDMSG]);
9991 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9992
9993 qstatus = GetQueueStatus(qs_all_input);
9994 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9995 "wrong qstatus %08x\n", qstatus);
9996
9997 msg.message = 0;
9998 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9999 ok(!ret,
10000 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10001 msg.message);
10002 ok_sequence(WmUser, "WmUser", FALSE);
10003
10004 qstatus = GetQueueStatus(qs_all_input);
10005 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
10006 "wrong qstatus %08x\n", qstatus);
10007
10008 msg.message = 0;
10009 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
10010 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
10011 else /* workaround for a missing QS_RAWINPUT support */
10012 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
10013 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10014 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10015 ret, msg.message, msg.wParam);
10016 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
10017
10018 qstatus = GetQueueStatus(qs_all_input);
10019 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
10020 "wrong qstatus %08x\n", qstatus);
10021
10022 msg.message = 0;
10023 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
10024 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
10025 else /* workaround for a missing QS_RAWINPUT support */
10026 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
10027 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
10028 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
10029 ret, msg.message, msg.wParam);
10030 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
10031
10032 qstatus = GetQueueStatus(qs_all_input);
10033 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10034 "wrong qstatus %08x\n", qstatus);
10035
10036 msg.message = 0;
10037 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
10038 ok(!ret,
10039 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10040 msg.message);
10041 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10042
10043 qstatus = GetQueueStatus(qs_all_input);
10044 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10045 "wrong qstatus %08x\n", qstatus);
10046
10047 msg.message = 0;
10048 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10049 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10050 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10051 ret, msg.message, msg.wParam);
10052 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10053
10054 qstatus = GetQueueStatus(qs_all_input);
10055 ok(qstatus == 0,
10056 "wrong qstatus %08x\n", qstatus);
10057
10058 msg.message = 0;
10059 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10060 ok(!ret,
10061 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10062 msg.message);
10063 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10064
10065 qstatus = GetQueueStatus(qs_all_input);
10066 ok(qstatus == 0,
10067 "wrong qstatus %08x\n", qstatus);
10068
10069 /* test whether presence of the quit flag in the queue affects
10070 * the queue state
10071 */
10072 PostQuitMessage(0x1234abcd);
10073
10074 qstatus = GetQueueStatus(qs_all_input);
10075 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
10076 "wrong qstatus %08x\n", qstatus);
10077
10078 PostMessageA(info.hwnd, WM_USER, 0, 0);
10079
10080 qstatus = GetQueueStatus(qs_all_input);
10081 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
10082 "wrong qstatus %08x\n", qstatus);
10083
10084 msg.message = 0;
10085 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10086 ok(ret && msg.message == WM_USER,
10087 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
10088 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10089
10090 qstatus = GetQueueStatus(qs_all_input);
10091 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10092 "wrong qstatus %08x\n", qstatus);
10093
10094 msg.message = 0;
10095 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10096 ok(ret && msg.message == WM_QUIT,
10097 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
10098 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
10099 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
10100 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10101
10102 qstatus = GetQueueStatus(qs_all_input);
10103 todo_wine {
10104 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
10105 "wrong qstatus %08x\n", qstatus);
10106 }
10107
10108 msg.message = 0;
10109 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10110 ok(!ret,
10111 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10112 msg.message);
10113 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
10114
10115 qstatus = GetQueueStatus(qs_all_input);
10116 ok(qstatus == 0,
10117 "wrong qstatus %08x\n", qstatus);
10118
10119 /* some GetMessage tests */
10120
10121 keybd_event('N', 0, 0, 0);
10122 qstatus = GetQueueStatus(qs_all_input);
10123 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10124
10125 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10126 qstatus = GetQueueStatus(qs_all_input);
10127 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10128
10129 if (qstatus)
10130 {
10131 ret = GetMessageA( &msg, 0, 0, 0 );
10132 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10133 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10134 ret, msg.message, msg.wParam);
10135 qstatus = GetQueueStatus(qs_all_input);
10136 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
10137 }
10138
10139 if (qstatus)
10140 {
10141 ret = GetMessageA( &msg, 0, 0, 0 );
10142 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10143 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10144 ret, msg.message, msg.wParam);
10145 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
10146 qstatus = GetQueueStatus(qs_all_input);
10147 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10148 }
10149
10150 keybd_event('N', 0, 0, 0);
10151 qstatus = GetQueueStatus(qs_all_input);
10152 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10153
10154 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10155 qstatus = GetQueueStatus(qs_all_input);
10156 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10157
10158 if (qstatus & (QS_KEY << 16))
10159 {
10160 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
10161 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
10162 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10163 ret, msg.message, msg.wParam);
10164 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
10165 qstatus = GetQueueStatus(qs_all_input);
10166 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
10167 }
10168
10169 if (qstatus)
10170 {
10171 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
10172 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10173 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10174 ret, msg.message, msg.wParam);
10175 qstatus = GetQueueStatus(qs_all_input);
10176 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10177 }
10178
10179 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10180 qstatus = GetQueueStatus(qs_all_input);
10181 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
10182
10183 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
10184 qstatus = GetQueueStatus(qs_all_input);
10185 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
10186
10187 trace("signalling to send message\n");
10188 SetEvent(info.hevent[EV_SENDMSG]);
10189 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10190 qstatus = GetQueueStatus(qs_all_input);
10191 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
10192 "wrong qstatus %08x\n", qstatus);
10193
10194 if (qstatus & (QS_KEY << 16))
10195 {
10196 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
10197 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
10198 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
10199 ret, msg.message, msg.wParam);
10200 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
10201 qstatus = GetQueueStatus(qs_all_input);
10202 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
10203 }
10204
10205 if (qstatus)
10206 {
10207 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
10208 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
10209 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
10210 ret, msg.message, msg.wParam);
10211 qstatus = GetQueueStatus(qs_all_input);
10212 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10213 }
10214 done:
10215 trace("signalling to exit\n");
10216 SetEvent(info.hevent[EV_STOP]);
10217
10218 WaitForSingleObject(hthread, INFINITE);
10219
10220 CloseHandle(hthread);
10221 CloseHandle(info.hevent[0]);
10222 CloseHandle(info.hevent[1]);
10223 CloseHandle(info.hevent[2]);
10224
10225 DestroyWindow(info.hwnd);
10226 }
10227
10228 static void wait_move_event(HWND hwnd, int x, int y)
10229 {
10230 MSG msg;
10231 DWORD time;
10232 BOOL ret;
10233 int go = 0;
10234
10235 time = GetTickCount();
10236 while (GetTickCount() - time < 200 && !go) {
10237 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10238 go = ret && msg.pt.x > x && msg.pt.y > y;
10239 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
10240 }
10241 }
10242
10243 #define STEP 5
10244 static void test_PeekMessage2(void)
10245 {
10246 HWND hwnd;
10247 BOOL ret;
10248 MSG msg;
10249 UINT message;
10250 DWORD time1, time2, time3;
10251 int x1, y1, x2, y2, x3, y3;
10252 POINT pos;
10253
10254 time1 = time2 = time3 = 0;
10255 x1 = y1 = x2 = y2 = x3 = y3 = 0;
10256
10257 /* Initialise window and make sure it is ready for events */
10258 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
10259 10, 10, 800, 800, NULL, NULL, NULL, NULL);
10260 assert(hwnd);
10261 trace("Window for test_PeekMessage2 %p\n", hwnd);
10262 ShowWindow(hwnd, SW_SHOW);
10263 UpdateWindow(hwnd);
10264 SetFocus(hwnd);
10265 GetCursorPos(&pos);
10266 SetCursorPos(100, 100);
10267 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
10268 flush_events();
10269
10270 /* Do initial mousemove, wait until we can see it
10271 and then do our test peek with PM_NOREMOVE. */
10272 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10273 wait_move_event(hwnd, 100-STEP, 100-STEP);
10274
10275 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10276 if (!ret)
10277 {
10278 skip( "queuing mouse events not supported\n" );
10279 goto done;
10280 }
10281 else
10282 {
10283 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10284 message = msg.message;
10285 time1 = msg.time;
10286 x1 = msg.pt.x;
10287 y1 = msg.pt.y;
10288 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10289 }
10290
10291 /* Allow time to advance a bit, and then simulate the user moving their
10292 * mouse around. After that we peek again with PM_NOREMOVE.
10293 * Although the previous mousemove message was never removed, the
10294 * mousemove we now peek should reflect the recent mouse movements
10295 * because the input queue will merge the move events. */
10296 Sleep(100);
10297 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10298 wait_move_event(hwnd, x1, y1);
10299
10300 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10301 ok(ret, "no message available\n");
10302 if (ret) {
10303 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10304 message = msg.message;
10305 time2 = msg.time;
10306 x2 = msg.pt.x;
10307 y2 = msg.pt.y;
10308 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10309 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
10310 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
10311 }
10312
10313 /* Have another go, to drive the point home */
10314 Sleep(100);
10315 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10316 wait_move_event(hwnd, x2, y2);
10317
10318 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10319 ok(ret, "no message available\n");
10320 if (ret) {
10321 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10322 message = msg.message;
10323 time3 = msg.time;
10324 x3 = msg.pt.x;
10325 y3 = msg.pt.y;
10326 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10327 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
10328 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
10329 }
10330
10331 done:
10332 DestroyWindow(hwnd);
10333 SetCursorPos(pos.x, pos.y);
10334 flush_events();
10335 }
10336
10337 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10338 {
10339 struct recvd_message msg;
10340
10341 if (ignore_message( message )) return 0;
10342
10343 msg.hwnd = hwnd;
10344 msg.message = message;
10345 msg.flags = sent|wparam|lparam;
10346 msg.wParam = wp;
10347 msg.lParam = lp;
10348 msg.descr = "dialog";
10349 add_message(&msg);
10350
10351 switch (message)
10352 {
10353 case WM_INITDIALOG:
10354 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
10355 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
10356 return 0;
10357
10358 case WM_GETDLGCODE:
10359 return 0;
10360
10361 case WM_USER:
10362 EndDialog(hwnd, 0);
10363 break;
10364 }
10365
10366 return 1;
10367 }
10368
10369 static const struct message WmQuitDialogSeq[] = {
10370 { HCBT_CREATEWND, hook },
10371 { WM_SETFONT, sent },
10372 { WM_INITDIALOG, sent },
10373 { WM_CHANGEUISTATE, sent|optional },
10374 { HCBT_DESTROYWND, hook },
10375 { 0x0090, sent|optional }, /* Vista */
10376 { WM_DESTROY, sent },
10377 { WM_NCDESTROY, sent },
10378 { 0 }
10379 };
10380
10381 static const struct message WmStopQuitSeq[] = {
10382 { WM_DWMNCRENDERINGCHANGED, posted|optional },
10383 { WM_CLOSE, posted },
10384 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
10385 { 0 }
10386 };
10387
10388 static void test_quit_message(void)
10389 {
10390 MSG msg;
10391 BOOL ret;
10392
10393 /* test using PostQuitMessage */
10394 flush_events();
10395 PostQuitMessage(0xbeef);
10396
10397 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
10398 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10399 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10400 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10401
10402 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
10403 ok(ret, "PostMessage failed with error %d\n", GetLastError());
10404
10405 ret = GetMessageA(&msg, NULL, 0, 0);
10406 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10407 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10408
10409 /* note: WM_QUIT message received after WM_USER message */
10410 ret = GetMessageA(&msg, NULL, 0, 0);
10411 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10412 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10413 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10414
10415 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
10416 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
10417
10418 /* now test with PostThreadMessage - different behaviour! */
10419 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
10420
10421 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
10422 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10423 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10424 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10425
10426 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
10427 ok(ret, "PostMessage failed with error %d\n", GetLastError());
10428
10429 /* note: we receive the WM_QUIT message first this time */
10430 ret = GetMessageA(&msg, NULL, 0, 0);
10431 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10432 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10433 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10434
10435 ret = GetMessageA(&msg, NULL, 0, 0);
10436 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10437 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10438
10439 flush_events();
10440 flush_sequence();
10441 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
10442 ok(ret == 1, "expected 1, got %d\n", ret);
10443 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
10444 memset(&msg, 0xab, sizeof(msg));
10445 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
10446 ok(ret, "PeekMessage failed\n");
10447 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10448 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
10449 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
10450
10451 /* Check what happens to a WM_QUIT message posted to a window that gets
10452 * destroyed.
10453 */
10454 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
10455 0, 0, 100, 100, NULL, NULL, NULL, NULL);
10456 flush_sequence();
10457 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10458 {
10459 struct recvd_message rmsg;
10460 rmsg.hwnd = msg.hwnd;
10461 rmsg.message = msg.message;
10462 rmsg.flags = posted|wparam|lparam;
10463 rmsg.wParam = msg.wParam;
10464 rmsg.lParam = msg.lParam;
10465 rmsg.descr = "stop/quit";
10466 if (msg.message == WM_QUIT)
10467 /* The hwnd can only be checked here */
10468 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
10469 add_message(&rmsg);
10470 DispatchMessageA(&msg);
10471 }
10472 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
10473 }
10474
10475 static const struct message WmMouseHoverSeq[] = {
10476 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
10477 { WM_MOUSEACTIVATE, sent|optional },
10478 { WM_TIMER, sent|optional }, /* XP sends it */
10479 { WM_SYSTIMER, sent },
10480 { WM_MOUSEHOVER, sent|wparam, 0 },
10481 { 0 }
10482 };
10483
10484 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
10485 {
10486 MSG msg;
10487 DWORD start_ticks, end_ticks;
10488
10489 start_ticks = GetTickCount();
10490 /* add some deviation (50%) to cover not expected delays */
10491 start_ticks += timeout / 2;
10492
10493 do
10494 {
10495 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10496 {
10497 /* Timer proc messages are not dispatched to the window proc,
10498 * and therefore not logged.
10499 */
10500 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
10501 {
10502 struct recvd_message s_msg;
10503
10504 s_msg.hwnd = msg.hwnd;
10505 s_msg.message = msg.message;
10506 s_msg.flags = sent|wparam|lparam;
10507 s_msg.wParam = msg.wParam;
10508 s_msg.lParam = msg.lParam;
10509 s_msg.descr = "msg_loop";
10510 add_message(&s_msg);
10511 }
10512 DispatchMessageA(&msg);
10513 }
10514
10515 end_ticks = GetTickCount();
10516
10517 /* inject WM_MOUSEMOVE to see how it changes tracking */
10518 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
10519 {
10520 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10521 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10522
10523 inject_mouse_move = FALSE;
10524 }
10525 } while (start_ticks + timeout >= end_ticks);
10526 }
10527
10528 static void test_TrackMouseEvent(void)
10529 {
10530 TRACKMOUSEEVENT tme;
10531 BOOL ret;
10532 HWND hwnd, hchild;
10533 RECT rc_parent, rc_child;
10534 UINT default_hover_time, hover_width = 0, hover_height = 0;
10535
10536 #define track_hover(track_hwnd, track_hover_time) \
10537 tme.cbSize = sizeof(tme); \
10538 tme.dwFlags = TME_HOVER; \
10539 tme.hwndTrack = track_hwnd; \
10540 tme.dwHoverTime = track_hover_time; \
10541 SetLastError(0xdeadbeef); \
10542 ret = pTrackMouseEvent(&tme); \
10543 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
10544
10545 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
10546 tme.cbSize = sizeof(tme); \
10547 tme.dwFlags = TME_QUERY; \
10548 tme.hwndTrack = (HWND)0xdeadbeef; \
10549 tme.dwHoverTime = 0xdeadbeef; \
10550 SetLastError(0xdeadbeef); \
10551 ret = pTrackMouseEvent(&tme); \
10552 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
10553 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
10554 ok(tme.dwFlags == (expected_track_flags), \
10555 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
10556 ok(tme.hwndTrack == (expected_track_hwnd), \
10557 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
10558 ok(tme.dwHoverTime == (expected_hover_time), \
10559 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
10560
10561 #define track_hover_cancel(track_hwnd) \
10562 tme.cbSize = sizeof(tme); \
10563 tme.dwFlags = TME_HOVER | TME_CANCEL; \
10564 tme.hwndTrack = track_hwnd; \
10565 tme.dwHoverTime = 0xdeadbeef; \
10566 SetLastError(0xdeadbeef); \
10567 ret = pTrackMouseEvent(&tme); \
10568 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
10569
10570 default_hover_time = 0xdeadbeef;
10571 SetLastError(0xdeadbeef);
10572 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
10573 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10574 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
10575 if (!ret) default_hover_time = 400;
10576 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
10577
10578 SetLastError(0xdeadbeef);
10579 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
10580 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10581 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
10582 if (!ret) hover_width = 4;
10583 SetLastError(0xdeadbeef);
10584 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
10585 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
10586 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
10587 if (!ret) hover_height = 4;
10588 trace("hover rect is %u x %d\n", hover_width, hover_height);
10589
10590 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10591 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10592 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10593 NULL, NULL, 0);
10594 assert(hwnd);
10595
10596 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
10597 WS_CHILD | WS_BORDER | WS_VISIBLE,
10598 50, 50, 200, 200, hwnd,
10599 NULL, NULL, 0);
10600 assert(hchild);
10601
10602 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
10603 flush_events();
10604 flush_sequence();
10605
10606 tme.cbSize = 0;
10607 tme.dwFlags = TME_QUERY;
10608 tme.hwndTrack = (HWND)0xdeadbeef;
10609 tme.dwHoverTime = 0xdeadbeef;
10610 SetLastError(0xdeadbeef);
10611 ret = pTrackMouseEvent(&tme);
10612 ok(!ret, "TrackMouseEvent should fail\n");
10613 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
10614 "not expected error %u\n", GetLastError());
10615
10616 tme.cbSize = sizeof(tme);
10617 tme.dwFlags = TME_HOVER;
10618 tme.hwndTrack = (HWND)0xdeadbeef;
10619 tme.dwHoverTime = 0xdeadbeef;
10620 SetLastError(0xdeadbeef);
10621 ret = pTrackMouseEvent(&tme);
10622 ok(!ret, "TrackMouseEvent should fail\n");
10623 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10624 "not expected error %u\n", GetLastError());
10625
10626 tme.cbSize = sizeof(tme);
10627 tme.dwFlags = TME_HOVER | TME_CANCEL;
10628 tme.hwndTrack = (HWND)0xdeadbeef;
10629 tme.dwHoverTime = 0xdeadbeef;
10630 SetLastError(0xdeadbeef);
10631 ret = pTrackMouseEvent(&tme);
10632 ok(!ret, "TrackMouseEvent should fail\n");
10633 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10634 "not expected error %u\n", GetLastError());
10635
10636 GetWindowRect(hwnd, &rc_parent);
10637 GetWindowRect(hchild, &rc_child);
10638 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
10639
10640 /* Process messages so that the system updates its internal current
10641 * window and hittest, otherwise TrackMouseEvent calls don't have any
10642 * effect.
10643 */
10644 flush_events();
10645 flush_sequence();
10646
10647 track_query(0, NULL, 0);
10648 track_hover(hchild, 0);
10649 track_query(0, NULL, 0);
10650
10651 flush_events();
10652 flush_sequence();
10653
10654 track_hover(hwnd, 0);
10655 tme.cbSize = sizeof(tme);
10656 tme.dwFlags = TME_QUERY;
10657 tme.hwndTrack = (HWND)0xdeadbeef;
10658 tme.dwHoverTime = 0xdeadbeef;
10659 SetLastError(0xdeadbeef);
10660 ret = pTrackMouseEvent(&tme);
10661 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10662 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10663 if (!tme.dwFlags)
10664 {
10665 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10666 DestroyWindow( hwnd );
10667 return;
10668 }
10669 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10670 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10671 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10672 tme.dwHoverTime, default_hover_time);
10673
10674 pump_msg_loop_timeout(default_hover_time, FALSE);
10675 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10676
10677 track_query(0, NULL, 0);
10678
10679 track_hover(hwnd, HOVER_DEFAULT);
10680 track_query(TME_HOVER, hwnd, default_hover_time);
10681
10682 Sleep(default_hover_time / 2);
10683 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10684 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10685
10686 track_query(TME_HOVER, hwnd, default_hover_time);
10687
10688 pump_msg_loop_timeout(default_hover_time, FALSE);
10689 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10690
10691 track_query(0, NULL, 0);
10692
10693 track_hover(hwnd, HOVER_DEFAULT);
10694 track_query(TME_HOVER, hwnd, default_hover_time);
10695
10696 pump_msg_loop_timeout(default_hover_time, TRUE);
10697 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10698
10699 track_query(0, NULL, 0);
10700
10701 track_hover(hwnd, HOVER_DEFAULT);
10702 track_query(TME_HOVER, hwnd, default_hover_time);
10703 track_hover_cancel(hwnd);
10704
10705 DestroyWindow(hwnd);
10706
10707 #undef track_hover
10708 #undef track_query
10709 #undef track_hover_cancel
10710 }
10711
10712
10713 static const struct message WmSetWindowRgn[] = {
10714 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10715 { WM_NCCALCSIZE, sent|wparam, 1 },
10716 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10717 { WM_GETTEXT, sent|defwinproc|optional },
10718 { WM_ERASEBKGND, sent|optional },
10719 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10720 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10721 { 0 }
10722 };
10723
10724 static const struct message WmSetWindowRgn_no_redraw[] = {
10725 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10726 { WM_NCCALCSIZE, sent|wparam, 1 },
10727 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10728 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10729 { 0 }
10730 };
10731
10732 static const struct message WmSetWindowRgn_clear[] = {
10733 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10734 { WM_NCCALCSIZE, sent|wparam, 1 },
10735 { WM_NCPAINT, sent|optional },
10736 { WM_GETTEXT, sent|defwinproc|optional },
10737 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10738 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10739 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10740 { WM_NCPAINT, sent|optional },
10741 { WM_GETTEXT, sent|defwinproc|optional },
10742 { WM_ERASEBKGND, sent|optional },
10743 { WM_WINDOWPOSCHANGING, sent|optional },
10744 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10745 { WM_NCPAINT, sent|optional },
10746 { WM_GETTEXT, sent|defwinproc|optional },
10747 { WM_ERASEBKGND, sent|optional },
10748 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10749 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10750 { WM_NCPAINT, sent|optional },
10751 { WM_GETTEXT, sent|defwinproc|optional },
10752 { WM_ERASEBKGND, sent|optional },
10753 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10754 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10755 { 0 }
10756 };
10757
10758 static void test_SetWindowRgn(void)
10759 {
10760 HRGN hrgn;
10761 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10762 100, 100, 200, 200, 0, 0, 0, NULL);
10763 ok( hwnd != 0, "Failed to create overlapped window\n" );
10764
10765 ShowWindow( hwnd, SW_SHOW );
10766 UpdateWindow( hwnd );
10767 flush_events();
10768 flush_sequence();
10769
10770 trace("testing SetWindowRgn\n");
10771 hrgn = CreateRectRgn( 0, 0, 150, 150 );
10772 SetWindowRgn( hwnd, hrgn, TRUE );
10773 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10774
10775 hrgn = CreateRectRgn( 30, 30, 160, 160 );
10776 SetWindowRgn( hwnd, hrgn, FALSE );
10777 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10778
10779 hrgn = CreateRectRgn( 0, 0, 180, 180 );
10780 SetWindowRgn( hwnd, hrgn, TRUE );
10781 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10782
10783 SetWindowRgn( hwnd, 0, TRUE );
10784 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10785
10786 DestroyWindow( hwnd );
10787 }
10788
10789 /*************************** ShowWindow() test ******************************/
10790 static const struct message WmShowNormal[] = {
10791 { WM_SHOWWINDOW, sent|wparam, 1 },
10792 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10793 { HCBT_ACTIVATE, hook },
10794 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10795 { HCBT_SETFOCUS, hook },
10796 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10797 { 0 }
10798 };
10799 static const struct message WmShow[] = {
10800 { WM_SHOWWINDOW, sent|wparam, 1 },
10801 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10802 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10803 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10804 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10805 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10806 { 0 }
10807 };
10808 static const struct message WmShowNoActivate_1[] = {
10809 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10810 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10811 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10812 { WM_MOVE, sent|defwinproc|optional },
10813 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10814 { 0 }
10815 };
10816 static const struct message WmShowNoActivate_2[] = {
10817 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10818 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10819 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10820 { WM_MOVE, sent|defwinproc },
10821 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10822 { HCBT_SETFOCUS, hook|optional },
10823 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10824 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10825 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10826 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10827 { 0 }
10828 };
10829 static const struct message WmShowNA_1[] = {
10830 { WM_SHOWWINDOW, sent|wparam, 1 },
10831 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10832 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10833 { 0 }
10834 };
10835 static const struct message WmShowNA_2[] = {
10836 { WM_SHOWWINDOW, sent|wparam, 1 },
10837 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10838 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10839 { 0 }
10840 };
10841 static const struct message WmRestore_1[] = {
10842 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10843 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10844 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10845 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10846 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10847 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10848 { WM_MOVE, sent|defwinproc },
10849 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10850 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10851 { 0 }
10852 };
10853 static const struct message WmRestore_2[] = {
10854 { WM_SHOWWINDOW, sent|wparam, 1 },
10855 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10856 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10857 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10858 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10859 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10860 { 0 }
10861 };
10862 static const struct message WmRestore_3[] = {
10863 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10864 { WM_GETMINMAXINFO, sent },
10865 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10866 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10867 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10868 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10869 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10870 { WM_MOVE, sent|defwinproc },
10871 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10872 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10873 { 0 }
10874 };
10875 static const struct message WmRestore_4[] = {
10876 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10877 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10878 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10879 { WM_MOVE, sent|defwinproc|optional },
10880 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10881 { 0 }
10882 };
10883 static const struct message WmRestore_5[] = {
10884 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10885 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10886 { HCBT_ACTIVATE, hook|optional },
10887 { HCBT_SETFOCUS, hook|optional },
10888 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10889 { WM_MOVE, sent|defwinproc|optional },
10890 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10891 { 0 }
10892 };
10893 static const struct message WmHide_1[] = {
10894 { WM_SHOWWINDOW, sent|wparam, 0 },
10895 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
10896 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
10897 { HCBT_ACTIVATE, hook|optional },
10898 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10899 { 0 }
10900 };
10901 static const struct message WmHide_2[] = {
10902 { WM_SHOWWINDOW, sent|wparam, 0 },
10903 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10904 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10905 { HCBT_ACTIVATE, hook|optional },
10906 { 0 }
10907 };
10908 static const struct message WmHide_3[] = {
10909 { WM_SHOWWINDOW, sent|wparam, 0 },
10910 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10911 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10912 { HCBT_SETFOCUS, hook|optional },
10913 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10914 { 0 }
10915 };
10916 static const struct message WmShowMinimized_1[] = {
10917 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10918 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10919 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10920 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10921 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10922 { WM_MOVE, sent|defwinproc },
10923 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10924 { 0 }
10925 };
10926 static const struct message WmMinimize_1[] = {
10927 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10928 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10929 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10930 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10931 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10932 { WM_MOVE, sent|defwinproc },
10933 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10934 { 0 }
10935 };
10936 static const struct message WmMinimize_2[] = {
10937 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10938 { HCBT_SETFOCUS, hook|optional },
10939 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10940 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10941 { WM_MOVE, sent|defwinproc },
10942 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10943 { 0 }
10944 };
10945 static const struct message WmMinimize_3[] = {
10946 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10947 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10948 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10949 { WM_MOVE, sent|defwinproc },
10950 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10951 { 0 }
10952 };
10953 static const struct message WmShowMinNoActivate[] = {
10954 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10955 { WM_WINDOWPOSCHANGING, sent },
10956 { WM_WINDOWPOSCHANGED, sent },
10957 { WM_MOVE, sent|defwinproc|optional },
10958 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10959 { 0 }
10960 };
10961 static const struct message WmMinMax_1[] = {
10962 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10963 { 0 }
10964 };
10965 static const struct message WmMinMax_2[] = {
10966 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10967 { WM_GETMINMAXINFO, sent|optional },
10968 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10969 { HCBT_ACTIVATE, hook|optional },
10970 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10971 { HCBT_SETFOCUS, hook|optional },
10972 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10973 { WM_MOVE, sent|defwinproc|optional },
10974 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10975 { HCBT_SETFOCUS, hook|optional },
10976 { 0 }
10977 };
10978 static const struct message WmMinMax_3[] = {
10979 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10980 { HCBT_SETFOCUS, hook|optional },
10981 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10982 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10983 { WM_MOVE, sent|defwinproc|optional },
10984 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10985 { 0 }
10986 };
10987 static const struct message WmMinMax_4[] = {
10988 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10989 { 0 }
10990 };
10991 static const struct message WmShowMaximized_1[] = {
10992 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10993 { WM_GETMINMAXINFO, sent },
10994 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10995 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10996 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10997 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10998 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10999 { WM_MOVE, sent|defwinproc },
11000 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11001 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
11002 { 0 }
11003 };
11004 static const struct message WmShowMaximized_2[] = {
11005 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11006 { WM_GETMINMAXINFO, sent },
11007 { WM_WINDOWPOSCHANGING, sent|optional },
11008 { HCBT_ACTIVATE, hook|optional },
11009 { WM_WINDOWPOSCHANGED, sent|optional },
11010 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
11011 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
11012 { WM_WINDOWPOSCHANGING, sent|optional },
11013 { HCBT_SETFOCUS, hook|optional },
11014 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
11015 { WM_MOVE, sent|defwinproc },
11016 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11017 { HCBT_SETFOCUS, hook|optional },
11018 { 0 }
11019 };
11020 static const struct message WmShowMaximized_3[] = {
11021 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
11022 { WM_GETMINMAXINFO, sent|optional },
11023 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
11024 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
11025 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
11026 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
11027 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
11028 { WM_MOVE, sent|defwinproc|optional },
11029 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
11030 { 0 }
11031 };
11032
11033 static void test_ShowWindow(void)
11034 {
11035 /* ShowWindow commands in random order */
11036 static const struct
11037 {
11038 INT cmd; /* ShowWindow command */
11039 LPARAM ret; /* ShowWindow return value */
11040 DWORD style; /* window style after the command */
11041 const struct message *msg; /* message sequence the command produces */
11042 INT wp_cmd, wp_flags; /* window placement after the command */
11043 POINT wp_min, wp_max; /* window placement after the command */
11044 BOOL todo_msg; /* message sequence doesn't match what Wine does */
11045 } sw[] =
11046 {
11047 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
11048 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11049 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
11050 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11051 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
11052 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11053 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11054 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
11055 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
11056 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11057 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
11058 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11059 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
11060 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11061 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11062 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11063 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
11064 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11065 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
11066 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11067 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
11068 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11069 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
11070 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11071 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
11072 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11073 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
11074 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11075 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
11076 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11077 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11078 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11079 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
11080 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11081 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
11082 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11083 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
11084 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11085 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11086 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11087 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11088 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11089 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
11090 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
11091 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
11092 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11093 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11094 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11095 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11096 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11097 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
11098 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11099 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
11100 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11101 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11102 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11103 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
11104 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11105 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
11106 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11107 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
11108 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11109 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
11110 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11111 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11112 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11113 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
11114 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11115 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
11116 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11117 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11118 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11119 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
11120 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11121 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
11122 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11123 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
11124 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11125 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
11126 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11127 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11128 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11129 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
11130 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11131 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
11132 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11133 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
11134 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11135 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
11136 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11137 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
11138 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11139 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
11140 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11141 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
11142 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11143 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
11144 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11145 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
11146 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11147 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
11148 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11149 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
11150 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11151 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
11152 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
11153 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
11154 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11155 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
11156 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
11157 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
11158 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
11159 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
11160 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
11161 };
11162 HWND hwnd;
11163 DWORD style;
11164 LPARAM ret;
11165 INT i;
11166 WINDOWPLACEMENT wp;
11167 RECT win_rc, work_rc = {0, 0, 0, 0};
11168
11169 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
11170 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
11171 120, 120, 90, 90,
11172 0, 0, 0, NULL);
11173 assert(hwnd);
11174
11175 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
11176 ok(style == 0, "expected style 0, got %08x\n", style);
11177
11178 flush_events();
11179 flush_sequence();
11180
11181 if (pGetMonitorInfoA && pMonitorFromPoint)
11182 {
11183 HMONITOR hmon;
11184 MONITORINFO mi;
11185 POINT pt = {0, 0};
11186
11187 SetLastError(0xdeadbeef);
11188 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
11189 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
11190
11191 mi.cbSize = sizeof(mi);
11192 SetLastError(0xdeadbeef);
11193 ret = pGetMonitorInfoA(hmon, &mi);
11194 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
11195 trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n",
11196 mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom,
11197 mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
11198 work_rc = mi.rcWork;
11199 }
11200
11201 GetWindowRect(hwnd, &win_rc);
11202 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
11203
11204 wp.length = sizeof(wp);
11205 SetLastError(0xdeadbeaf);
11206 ret = GetWindowPlacement(hwnd, &wp);
11207 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11208 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
11209 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
11210 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
11211 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
11212 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
11213 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11214 if (work_rc.left || work_rc.top) todo_wine /* FIXME: remove once Wine is fixed */
11215 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11216 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11217 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11218 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11219 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11220 else
11221 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11222 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11223 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11224 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11225 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11226
11227 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
11228 {
11229 static const char * const sw_cmd_name[13] =
11230 {
11231 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
11232 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
11233 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
11234 "SW_NORMALNA" /* 0xCC */
11235 };
11236 char comment[64];
11237 INT idx; /* index into the above array of names */
11238
11239 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
11240
11241 style = GetWindowLongA(hwnd, GWL_STYLE);
11242 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
11243 ret = ShowWindow(hwnd, sw[i].cmd);
11244 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
11245 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
11246 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
11247
11248 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
11249 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
11250
11251 wp.length = sizeof(wp);
11252 SetLastError(0xdeadbeaf);
11253 ret = GetWindowPlacement(hwnd, &wp);
11254 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11255 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
11256 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
11257
11258 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
11259 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
11260 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
11261 {
11262 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
11263 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
11264 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11265 }
11266 else
11267 {
11268 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
11269 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11270 }
11271
11272 if (wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
11273 todo_wine
11274 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11275 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11276 else
11277 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11278 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11279
11280 if (0) /* FIXME: Wine behaves completely different here */
11281 ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11282 "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11283 win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11284 wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11285 wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11286
11287 flush_events();
11288 flush_sequence();
11289 }
11290
11291 DestroyWindow(hwnd);
11292 }
11293
11294 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11295 {
11296 struct recvd_message msg;
11297
11298 if (ignore_message( message )) return 0;
11299
11300 msg.hwnd = hwnd;
11301 msg.message = message;
11302 msg.flags = sent|wparam|lparam;
11303 msg.wParam = wParam;
11304 msg.lParam = lParam;
11305 msg.descr = "dialog";
11306 add_message(&msg);
11307
11308 /* calling DefDlgProc leads to a recursion under XP */
11309
11310 switch (message)
11311 {
11312 case WM_INITDIALOG:
11313 case WM_GETDLGCODE:
11314 return 0;
11315 }
11316 return 1;
11317 }
11318
11319 static const struct message WmDefDlgSetFocus_1[] = {
11320 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11321 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11322 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11323 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11324 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11325 { HCBT_SETFOCUS, hook },
11326 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11327 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11328 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11329 { WM_SETFOCUS, sent|wparam, 0 },
11330 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11331 { WM_CTLCOLOREDIT, sent },
11332 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11333 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11334 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11335 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11336 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
11337 { 0 }
11338 };
11339 static const struct message WmDefDlgSetFocus_2[] = {
11340 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11341 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11342 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11343 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11344 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11345 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11346 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
11347 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11348 { 0 }
11349 };
11350 /* Creation of a dialog */
11351 static const struct message WmCreateDialogParamSeq_1[] = {
11352 { HCBT_CREATEWND, hook },
11353 { WM_NCCREATE, sent },
11354 { WM_NCCALCSIZE, sent|wparam, 0 },
11355 { WM_CREATE, sent },
11356 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11357 { WM_SIZE, sent|wparam, SIZE_RESTORED },
11358 { WM_MOVE, sent },
11359 { WM_SETFONT, sent },
11360 { WM_INITDIALOG, sent },
11361 { WM_CHANGEUISTATE, sent|optional },
11362 { 0 }
11363 };
11364 /* Creation of a dialog */
11365 static const struct message WmCreateDialogParamSeq_2[] = {
11366 { HCBT_CREATEWND, hook },
11367 { WM_NCCREATE, sent },
11368 { WM_NCCALCSIZE, sent|wparam, 0 },
11369 { WM_CREATE, sent },
11370 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11371 { WM_SIZE, sent|wparam, SIZE_RESTORED },
11372 { WM_MOVE, sent },
11373 { WM_CHANGEUISTATE, sent|optional },
11374 { 0 }
11375 };
11376
11377 static void test_dialog_messages(void)
11378 {
11379 WNDCLASSA cls;
11380 HWND hdlg, hedit1, hedit2, hfocus;
11381 LRESULT ret;
11382
11383 #define set_selection(hctl, start, end) \
11384 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
11385 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
11386
11387 #define check_selection(hctl, start, end) \
11388 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
11389 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
11390
11391 subclass_edit();
11392
11393 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
11394 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
11395 0, 0, 100, 100, 0, 0, 0, NULL);
11396 ok(hdlg != 0, "Failed to create custom dialog window\n");
11397
11398 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
11399 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11400 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
11401 ok(hedit1 != 0, "Failed to create edit control\n");
11402 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
11403 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11404 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
11405 ok(hedit2 != 0, "Failed to create edit control\n");
11406
11407 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
11408 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
11409
11410 hfocus = GetFocus();
11411 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
11412
11413 SetFocus(hedit2);
11414 hfocus = GetFocus();
11415 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
11416
11417 check_selection(hedit1, 0, 0);
11418 check_selection(hedit2, 0, 0);
11419
11420 set_selection(hedit2, 0, -1);
11421 check_selection(hedit2, 0, 3);
11422
11423 SetFocus(0);
11424 hfocus = GetFocus();
11425 ok(hfocus == 0, "wrong focus %p\n", hfocus);
11426
11427 flush_sequence();
11428 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
11429 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11430 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
11431
11432 hfocus = GetFocus();
11433 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11434
11435 check_selection(hedit1, 0, 5);
11436 check_selection(hedit2, 0, 3);
11437
11438 flush_sequence();
11439 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
11440 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11441 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
11442
11443 hfocus = GetFocus();
11444 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11445
11446 check_selection(hedit1, 0, 5);
11447 check_selection(hedit2, 0, 3);
11448
11449 EndDialog(hdlg, 0);
11450 DestroyWindow(hedit1);
11451 DestroyWindow(hedit2);
11452 DestroyWindow(hdlg);
11453 flush_sequence();
11454
11455 #undef set_selection
11456 #undef check_selection
11457
11458 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11459 cls.lpszClassName = "MyDialogClass";
11460 cls.hInstance = GetModuleHandleA(NULL);
11461 /* need a cast since a dlgproc is used as a wndproc */
11462 cls.lpfnWndProc = test_dlg_proc;
11463 if (!RegisterClassA(&cls)) assert(0);
11464
11465 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
11466 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11467 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
11468 EndDialog(hdlg, 0);
11469 DestroyWindow(hdlg);
11470 flush_sequence();
11471
11472 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
11473 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11474 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
11475 EndDialog(hdlg, 0);
11476 DestroyWindow(hdlg);
11477 flush_sequence();
11478
11479 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11480 }
11481
11482 static void test_EndDialog(void)
11483 {
11484 HWND hparent, hother, hactive, hdlg;
11485 WNDCLASSA cls;
11486
11487 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
11488 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
11489 100, 100, 200, 200, 0, 0, 0, NULL);
11490 ok (hparent != 0, "Failed to create parent window\n");
11491
11492 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
11493 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11494 100, 100, 200, 200, 0, 0, 0, NULL);
11495 ok (hother != 0, "Failed to create parent window\n");
11496
11497 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11498 cls.lpszClassName = "MyDialogClass";
11499 cls.hInstance = GetModuleHandleA(NULL);
11500 cls.lpfnWndProc = test_dlg_proc;
11501 if (!RegisterClassA(&cls)) assert(0);
11502
11503 flush_sequence();
11504 SetForegroundWindow(hother);
11505 hactive = GetForegroundWindow();
11506 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
11507
11508 /* create a dialog where the parent is disabled, this parent should still
11509 receive the focus when the dialog exits (even though "normally" a
11510 disabled window should not receive the focus) */
11511 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
11512 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11513 SetForegroundWindow(hdlg);
11514 hactive = GetForegroundWindow();
11515 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
11516 EndDialog(hdlg, 0);
11517 hactive = GetForegroundWindow();
11518 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
11519 DestroyWindow(hdlg);
11520 flush_sequence();
11521
11522 DestroyWindow( hother );
11523 DestroyWindow( hparent );
11524 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11525 }
11526
11527 static void test_nullCallback(void)
11528 {
11529 HWND hwnd;
11530
11531 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
11532 100, 100, 200, 200, 0, 0, 0, NULL);
11533 ok (hwnd != 0, "Failed to create overlapped window\n");
11534
11535 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
11536 flush_events();
11537 DestroyWindow(hwnd);
11538 }
11539
11540 /* SetActiveWindow( 0 ) hwnd visible */
11541 static const struct message SetActiveWindowSeq0[] =
11542 {
11543 { HCBT_ACTIVATE, hook|optional },
11544 { WM_NCACTIVATE, sent|wparam, 0 },
11545 { WM_GETTEXT, sent|defwinproc|optional },
11546 { WM_ACTIVATE, sent|wparam, 0 },
11547 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11548 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11549 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11550 { WM_KILLFOCUS, sent|optional },
11551 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11552 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11553 { WM_NCACTIVATE, sent|wparam|optional, 1 },
11554 { WM_GETTEXT, sent|defwinproc|optional },
11555 { WM_ACTIVATE, sent|wparam|optional, 1 },
11556 { HCBT_SETFOCUS, hook|optional },
11557 { WM_KILLFOCUS, sent|defwinproc|optional },
11558 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11559 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11560 { WM_IME_SETCONTEXT, sent|optional },
11561 { WM_IME_SETCONTEXT, sent|optional },
11562 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11563 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11564 { WM_SETFOCUS, sent|defwinproc|optional },
11565 { WM_GETTEXT, sent|optional },
11566 { 0 }
11567 };
11568 /* SetActiveWindow( hwnd ) hwnd visible */
11569 static const struct message SetActiveWindowSeq1[] =
11570 {
11571 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11572 { 0 }
11573 };
11574 /* SetActiveWindow( popup ) hwnd visible, popup visible */
11575 static const struct message SetActiveWindowSeq2[] =
11576 {
11577 { HCBT_ACTIVATE, hook },
11578 { WM_NCACTIVATE, sent|wparam, 0 },
11579 { WM_GETTEXT, sent|defwinproc|optional },
11580 { WM_ACTIVATE, sent|wparam, 0 },
11581 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11582 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11583 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11584 { WM_NCPAINT, sent|optional },
11585 { WM_GETTEXT, sent|defwinproc|optional },
11586 { WM_ERASEBKGND, sent|optional },
11587 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11588 { WM_NCACTIVATE, sent|wparam, 1 },
11589 { WM_GETTEXT, sent|defwinproc|optional },
11590 { WM_ACTIVATE, sent|wparam, 1 },
11591 { HCBT_SETFOCUS, hook },
11592 { WM_KILLFOCUS, sent|defwinproc },
11593 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11594 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11595 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11596 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11597 { WM_SETFOCUS, sent|defwinproc },
11598 { WM_GETTEXT, sent|optional },
11599 { 0 }
11600 };
11601
11602 /* SetActiveWindow( hwnd ) hwnd not visible */
11603 static const struct message SetActiveWindowSeq3[] =
11604 {
11605 { HCBT_ACTIVATE, hook },
11606 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11607 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11608 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11609 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11610 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11611 { WM_ACTIVATEAPP, sent|wparam, 1 },
11612 { WM_ACTIVATEAPP, sent|wparam, 1 },
11613 { WM_NCACTIVATE, sent|wparam, 1 },
11614 { WM_ACTIVATE, sent|wparam, 1 },
11615 { HCBT_SETFOCUS, hook },
11616 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11617 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11618 { WM_SETFOCUS, sent|defwinproc },
11619 { 0 }
11620 };
11621 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
11622 static const struct message SetActiveWindowSeq4[] =
11623 {
11624 { HCBT_ACTIVATE, hook },
11625 { WM_NCACTIVATE, sent|wparam, 0 },
11626 { WM_GETTEXT, sent|defwinproc|optional },
11627 { WM_ACTIVATE, sent|wparam, 0 },
11628 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11629 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11630 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11631 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11632 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11633 { WM_NCACTIVATE, sent|wparam, 1 },
11634 { WM_GETTEXT, sent|defwinproc|optional },
11635 { WM_ACTIVATE, sent|wparam, 1 },
11636 { HCBT_SETFOCUS, hook },
11637 { WM_KILLFOCUS, sent|defwinproc },
11638 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11639 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11640 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11641 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11642 { WM_SETFOCUS, sent|defwinproc },
11643 { 0 }
11644 };
11645
11646
11647 static void test_SetActiveWindow(void)
11648 {
11649 HWND hwnd, popup, ret;
11650
11651 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11652 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11653 100, 100, 200, 200, 0, 0, 0, NULL);
11654
11655 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11656 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
11657 100, 100, 200, 200, hwnd, 0, 0, NULL);
11658
11659 ok(hwnd != 0, "Failed to create overlapped window\n");
11660 ok(popup != 0, "Failed to create popup window\n");
11661 SetForegroundWindow( popup );
11662 flush_sequence();
11663
11664 trace("SetActiveWindow(0)\n");
11665 ret = SetActiveWindow(0);
11666 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
11667 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
11668 flush_sequence();
11669
11670 trace("SetActiveWindow(hwnd), hwnd visible\n");
11671 ret = SetActiveWindow(hwnd);
11672 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
11673 flush_sequence();
11674
11675 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
11676 ret = SetActiveWindow(popup);
11677 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
11678 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
11679 flush_sequence();
11680
11681 ShowWindow(hwnd, SW_HIDE);
11682 ShowWindow(popup, SW_HIDE);
11683 flush_sequence();
11684
11685 trace("SetActiveWindow(hwnd), hwnd not visible\n");
11686 ret = SetActiveWindow(hwnd);
11687 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
11688 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
11689 flush_sequence();
11690
11691 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
11692 ret = SetActiveWindow(popup);
11693 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
11694 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
11695 flush_sequence();
11696
11697 trace("done\n");
11698
11699 DestroyWindow(hwnd);
11700 }
11701
11702 static const struct message SetForegroundWindowSeq[] =
11703 {
11704 { WM_NCACTIVATE, sent|wparam, 0 },
11705 { WM_GETTEXT, sent|defwinproc|optional },
11706 { WM_ACTIVATE, sent|wparam, 0 },
11707 { WM_ACTIVATEAPP, sent|wparam, 0 },
11708 { WM_KILLFOCUS, sent },
11709 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11710 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
11711 { 0 }
11712 };
11713
11714 static void test_SetForegroundWindow(void)
11715 {
11716 HWND hwnd;
11717
11718 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
11719 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11720 100, 100, 200, 200, 0, 0, 0, NULL);
11721 ok (hwnd != 0, "Failed to create overlapped window\n");
11722 SetForegroundWindow( hwnd );
11723 flush_sequence();
11724
11725 trace("SetForegroundWindow( 0 )\n");
11726 SetForegroundWindow( 0 );
11727 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
11728 trace("SetForegroundWindow( GetDesktopWindow() )\n");
11729 SetForegroundWindow( GetDesktopWindow() );
11730 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
11731 "foreground top level window", FALSE);
11732 trace("done\n");
11733
11734 DestroyWindow(hwnd);
11735 }
11736
11737 static void test_dbcs_wm_char(void)
11738 {
11739 BYTE dbch[2];
11740 WCHAR wch, bad_wch;
11741 HWND hwnd, hwnd2;
11742 MSG msg;
11743 DWORD time;
11744 POINT pt;
11745 DWORD_PTR res;
11746 CPINFOEXA cpinfo;
11747 UINT i, j, k;
11748 struct message wmCharSeq[2];
11749 BOOL ret;
11750
11751 if (!pGetCPInfoExA)
11752 {
11753 win_skip("GetCPInfoExA is not available\n");
11754 return;
11755 }
11756
11757 pGetCPInfoExA( CP_ACP, 0, &cpinfo );
11758 if (cpinfo.MaxCharSize != 2)
11759 {
11760 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
11761 return;
11762 }
11763
11764 dbch[0] = dbch[1] = 0;
11765 wch = 0;
11766 bad_wch = cpinfo.UnicodeDefaultChar;
11767 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
11768 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
11769 for (k = 128; k <= 255; k++)
11770 {
11771 char str[2];
11772 WCHAR wstr[2];
11773 str[0] = j;
11774 str[1] = k;
11775 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
11776 WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
11777 (BYTE)str[0] == j && (BYTE)str[1] == k &&
11778 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
11779 {
11780 dbch[0] = j;
11781 dbch[1] = k;
11782 wch = wstr[0];
11783 break;
11784 }
11785 }
11786
11787 if (!wch)
11788 {
11789 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
11790 return;
11791 }
11792 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
11793 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
11794
11795 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
11796 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11797 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
11798 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11799 ok (hwnd != 0, "Failed to create overlapped window\n");
11800 ok (hwnd2 != 0, "Failed to create overlapped window\n");
11801 flush_sequence();
11802
11803 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
11804 wmCharSeq[0].message = WM_CHAR;
11805 wmCharSeq[0].flags = sent|wparam;
11806 wmCharSeq[0].wParam = wch;
11807
11808 /* posted message */
11809 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11810 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11811 ok( !ret, "got message %x\n", msg.message );
11812 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11813 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11814 ok( ret, "no message\n" );
11815 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11816 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11817 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11818 ok( !ret, "got message %x\n", msg.message );
11819
11820 /* posted thread message */
11821 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
11822 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11823 ok( !ret, "got message %x\n", msg.message );
11824 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11825 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11826 ok( ret, "no message\n" );
11827 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11828 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11829 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11830 ok( !ret, "got message %x\n", msg.message );
11831
11832 /* sent message */
11833 flush_sequence();
11834 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11835 ok_sequence( WmEmptySeq, "no messages", FALSE );
11836 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11837 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11838 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11839 ok( !ret, "got message %x\n", msg.message );
11840
11841 /* sent message with timeout */
11842 flush_sequence();
11843 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11844 ok_sequence( WmEmptySeq, "no messages", FALSE );
11845 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11846 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11847 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11848 ok( !ret, "got message %x\n", msg.message );
11849
11850 /* sent message with timeout and callback */
11851 flush_sequence();
11852 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11853 ok_sequence( WmEmptySeq, "no messages", FALSE );
11854 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11855 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11856 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11857 ok( !ret, "got message %x\n", msg.message );
11858
11859 /* sent message with callback */
11860 flush_sequence();
11861 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11862 ok_sequence( WmEmptySeq, "no messages", FALSE );
11863 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11864 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11865 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11866 ok( !ret, "got message %x\n", msg.message );
11867
11868 /* direct window proc call */
11869 flush_sequence();
11870 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11871 ok_sequence( WmEmptySeq, "no messages", FALSE );
11872 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11873 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11874
11875 /* dispatch message */
11876 msg.hwnd = hwnd;
11877 msg.message = WM_CHAR;
11878 msg.wParam = dbch[0];
11879 msg.lParam = 0;
11880 DispatchMessageA( &msg );
11881 ok_sequence( WmEmptySeq, "no messages", FALSE );
11882 msg.wParam = dbch[1];
11883 DispatchMessageA( &msg );
11884 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11885
11886 /* window handle is irrelevant */
11887 flush_sequence();
11888 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11889 ok_sequence( WmEmptySeq, "no messages", FALSE );
11890 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11891 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11892 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11893 ok( !ret, "got message %x\n", msg.message );
11894
11895 /* interleaved post and send */
11896 flush_sequence();
11897 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11898 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11899 ok_sequence( WmEmptySeq, "no messages", FALSE );
11900 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11901 ok( !ret, "got message %x\n", msg.message );
11902 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11903 ok_sequence( WmEmptySeq, "no messages", FALSE );
11904 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11905 ok( ret, "no message\n" );
11906 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11907 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11908 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11909 ok( !ret, "got message %x\n", msg.message );
11910 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11911 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11912 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11913 ok( !ret, "got message %x\n", msg.message );
11914
11915 /* interleaved sent message and winproc */
11916 flush_sequence();
11917 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11918 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11919 ok_sequence( WmEmptySeq, "no messages", FALSE );
11920 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11921 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11922 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11923 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11924
11925 /* interleaved winproc and dispatch */
11926 msg.hwnd = hwnd;
11927 msg.message = WM_CHAR;
11928 msg.wParam = dbch[0];
11929 msg.lParam = 0;
11930 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11931 DispatchMessageA( &msg );
11932 ok_sequence( WmEmptySeq, "no messages", FALSE );
11933 msg.wParam = dbch[1];
11934 DispatchMessageA( &msg );
11935 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11936 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11937 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11938
11939 /* interleaved sends */
11940 flush_sequence();
11941 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11942 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
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 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11947 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11948
11949 /* dbcs WM_CHAR */
11950 flush_sequence();
11951 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11952 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11953 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11954 ok( !ret, "got message %x\n", msg.message );
11955
11956 /* other char messages are not magic */
11957 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11958 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11959 ok( ret, "no message\n" );
11960 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11961 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11962 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11963 ok( !ret, "got message %x\n", msg.message );
11964 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11965 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11966 ok( ret, "no message\n" );
11967 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11968 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11969 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11970 ok( !ret, "got message %x\n", msg.message );
11971
11972 /* test retrieving messages */
11973
11974 PostMessageW( hwnd, WM_CHAR, wch, 0 );
11975 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11976 ok( ret, "no message\n" );
11977 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11978 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11979 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11980 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11981 ok( ret, "no message\n" );
11982 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11983 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11984 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11985 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11986 ok( !ret, "got message %x\n", msg.message );
11987
11988 /* message filters */
11989 PostMessageW( hwnd, WM_CHAR, wch, 0 );
11990 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11991 ok( ret, "no message\n" );
11992 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11993 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11994 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11995 /* message id is filtered, hwnd is not */
11996 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
11997 ok( !ret, "no message\n" );
11998 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
11999 ok( ret, "no message\n" );
12000 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12001 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12002 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12003 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12004 ok( !ret, "got message %x\n", msg.message );
12005
12006 /* mixing GetMessage and PostMessage */
12007 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
12008 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12009 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12010 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12011 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12012 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
12013 time = msg.time;
12014 pt = msg.pt;
12015 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
12016 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12017 ok( ret, "no message\n" );
12018 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12019 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12020 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12021 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
12022 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
12023 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 );
12024 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12025 ok( !ret, "got message %x\n", msg.message );
12026
12027 /* without PM_REMOVE */
12028 PostMessageW( hwnd, WM_CHAR, wch, 0 );
12029 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
12030 ok( ret, "no message\n" );
12031 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12032 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12033 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12034 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12035 ok( ret, "no message\n" );
12036 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12037 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12038 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12039 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
12040 ok( ret, "no message\n" );
12041 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12042 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12043 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12044 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
12045 ok( ret, "no message\n" );
12046 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12047 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12048 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
12049 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
12050 ok( !ret, "got message %x\n", msg.message );
12051
12052 DestroyWindow(hwnd);
12053 DestroyWindow(hwnd2);
12054 }
12055
12056 static void test_unicode_wm_char(void)
12057 {
12058 HWND hwnd;
12059 MSG msg;
12060 struct message seq[2];
12061 HKL hkl_orig, hkl_greek;
12062 DWORD cp;
12063 LCID thread_locale;
12064
12065 hkl_orig = GetKeyboardLayout( 0 );
12066 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
12067 if (cp != 1252)
12068 {
12069 skip( "Default codepage %d\n", cp );
12070 return;
12071 }
12072
12073 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
12074 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
12075 {
12076 skip( "Unable to load Greek keyboard layout\n" );
12077 return;
12078 }
12079
12080 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
12081 100, 100, 200, 200, 0, 0, 0, NULL );
12082 flush_sequence();
12083
12084 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12085
12086 ok( GetMessageW( &msg, hwnd, 0, 0 ), "no message\n" );
12087 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12088 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12089 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
12090 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12091
12092 DispatchMessageW( &msg );
12093
12094 memset( seq, 0, sizeof(seq) );
12095 seq[0].message = WM_CHAR;
12096 seq[0].flags = sent|wparam;
12097 seq[0].wParam = 0x3b1;
12098
12099 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12100
12101 flush_sequence();
12102
12103 /* greek alpha -> 'a' in cp1252 */
12104 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12105
12106 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12107 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12108 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12109 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
12110 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12111
12112 DispatchMessageA( &msg );
12113
12114 seq[0].wParam = 0x61;
12115 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12116
12117 thread_locale = GetThreadLocale();
12118 ActivateKeyboardLayout( hkl_greek, 0 );
12119 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
12120 thread_locale, GetThreadLocale() );
12121
12122 flush_sequence();
12123
12124 /* greek alpha -> 0xe1 in cp1253 */
12125 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
12126
12127 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
12128 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
12129 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
12130 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
12131 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
12132
12133 DispatchMessageA( &msg );
12134
12135 seq[0].wParam = 0x3b1;
12136 ok_sequence( seq, "unicode WM_CHAR", FALSE );
12137
12138 DestroyWindow( hwnd );
12139 ActivateKeyboardLayout( hkl_orig, 0 );
12140 UnloadKeyboardLayout( hkl_greek );
12141 }
12142
12143 #define ID_LISTBOX 0x000f
12144
12145 static const struct message wm_lb_setcursel_0[] =
12146 {
12147 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
12148 { WM_CTLCOLORLISTBOX, sent|parent },
12149 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
12150 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12151 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12152 { 0 }
12153 };
12154 static const struct message wm_lb_setcursel_1[] =
12155 {
12156 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
12157 { WM_CTLCOLORLISTBOX, sent|parent },
12158 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
12159 { WM_CTLCOLORLISTBOX, sent|parent },
12160 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
12161 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
12162 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
12163 { 0 }
12164 };
12165 static const struct message wm_lb_setcursel_2[] =
12166 {
12167 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
12168 { WM_CTLCOLORLISTBOX, sent|parent },
12169 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
12170 { WM_CTLCOLORLISTBOX, sent|parent },
12171 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
12172 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12173 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12174 { 0 }
12175 };
12176 static const struct message wm_lb_click_0[] =
12177 {
12178 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
12179 { HCBT_SETFOCUS, hook },
12180 { WM_KILLFOCUS, sent|parent },
12181 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
12182 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
12183 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12184 { WM_SETFOCUS, sent|defwinproc },
12185
12186 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
12187 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
12188 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
12189 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
12190 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
12191
12192 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
12193 { WM_CTLCOLORLISTBOX, sent|parent },
12194 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
12195 { WM_CTLCOLORLISTBOX, sent|parent },
12196 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
12197 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
12198
12199 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12200 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
12201
12202 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
12203 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
12204 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
12205 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
12206 { 0 }
12207 };
12208 static const struct message wm_lb_deletestring[] =
12209 {
12210 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
12211 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
12212 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12213 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12214 { 0 }
12215 };
12216 static const struct message wm_lb_deletestring_reset[] =
12217 {
12218 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
12219 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
12220 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
12221 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12222 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
12223 { 0 }
12224 };
12225
12226 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
12227
12228 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
12229
12230 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12231 {
12232 static LONG defwndproc_counter = 0;
12233 LRESULT ret;
12234 struct recvd_message msg;
12235
12236 /* do not log painting messages */
12237 if (message != WM_PAINT &&
12238 message != WM_NCPAINT &&
12239 message != WM_SYNCPAINT &&
12240 message != WM_ERASEBKGND &&
12241 message != WM_NCHITTEST &&
12242 message != WM_GETTEXT &&
12243 !ignore_message( message ))
12244 {
12245 msg.hwnd = hwnd;
12246 msg.message = message;
12247 msg.flags = sent|wparam|lparam;
12248 if (defwndproc_counter) msg.flags |= defwinproc;
12249 msg.wParam = wp;
12250 msg.lParam = lp;
12251 msg.descr = "listbox";
12252 add_message(&msg);
12253 }
12254
12255 defwndproc_counter++;
12256 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
12257 defwndproc_counter--;
12258
12259 return ret;
12260 }
12261
12262 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
12263 int caret_index, int top_index, int line)
12264 {
12265 LRESULT ret;
12266
12267 /* calling an orig proc helps to avoid unnecessary message logging */
12268 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
12269 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
12270 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
12271 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
12272 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
12273 ok_(__FILE__, line)(ret == caret_index ||
12274 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
12275 "expected caret index %d, got %ld\n", caret_index, ret);
12276 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
12277 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
12278 }
12279
12280 static void test_listbox_messages(void)
12281 {
12282 HWND parent, listbox;
12283 LRESULT ret;
12284
12285 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12286 100, 100, 200, 200, 0, 0, 0, NULL);
12287 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
12288 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
12289 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
12290 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
12291
12292 check_lb_state(listbox, 0, LB_ERR, 0, 0);
12293
12294 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
12295 ok(ret == 0, "expected 0, got %ld\n", ret);
12296 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
12297 ok(ret == 1, "expected 1, got %ld\n", ret);
12298 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
12299 ok(ret == 2, "expected 2, got %ld\n", ret);
12300
12301 check_lb_state(listbox, 3, LB_ERR, 0, 0);
12302
12303 flush_sequence();
12304
12305 log_all_parent_messages++;
12306
12307 trace("selecting item 0\n");
12308 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
12309 ok(ret == 0, "expected 0, got %ld\n", ret);
12310 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
12311 check_lb_state(listbox, 3, 0, 0, 0);
12312 flush_sequence();
12313
12314 trace("selecting item 1\n");
12315 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
12316 ok(ret == 1, "expected 1, got %ld\n", ret);
12317 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
12318 check_lb_state(listbox, 3, 1, 1, 0);
12319
12320 trace("selecting item 2\n");
12321 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
12322 ok(ret == 2, "expected 2, got %ld\n", ret);
12323 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
12324 check_lb_state(listbox, 3, 2, 2, 0);
12325
12326 trace("clicking on item 0\n");
12327 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
12328 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12329 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
12330 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12331 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
12332 check_lb_state(listbox, 3, 0, 0, 0);
12333 flush_sequence();
12334
12335 trace("deleting item 0\n");
12336 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12337 ok(ret == 2, "expected 2, got %ld\n", ret);
12338 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12339 check_lb_state(listbox, 2, -1, 0, 0);
12340 flush_sequence();
12341
12342 trace("deleting item 0\n");
12343 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12344 ok(ret == 1, "expected 1, got %ld\n", ret);
12345 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12346 check_lb_state(listbox, 1, -1, 0, 0);
12347 flush_sequence();
12348
12349 trace("deleting item 0\n");
12350 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12351 ok(ret == 0, "expected 0, got %ld\n", ret);
12352 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
12353 check_lb_state(listbox, 0, -1, 0, 0);
12354 flush_sequence();
12355
12356 trace("deleting item 0\n");
12357 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
12358 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
12359 check_lb_state(listbox, 0, -1, 0, 0);
12360 flush_sequence();
12361
12362 log_all_parent_messages--;
12363
12364 DestroyWindow(listbox);
12365 DestroyWindow(parent);
12366 }
12367
12368 /*************************** Menu test ******************************/
12369 static const struct message wm_popup_menu_1[] =
12370 {
12371 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12372 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12373 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
12374 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
12375 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
12376 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
12377 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12378 { WM_INITMENU, sent|lparam, 0, 0 },
12379 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
12380 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
12381 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
12382 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
12383 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
12384 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12385 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
12386 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
12387 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12388 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12389 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12390 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
12391 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12392 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12393 { 0 }
12394 };
12395 static const struct message wm_popup_menu_2[] =
12396 {
12397 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12398 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12399 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12400 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12401 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12402 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12403 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12404 { WM_INITMENU, sent|lparam, 0, 0 },
12405 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12406 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12407 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12408 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12409 { HCBT_CREATEWND, hook },
12410 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12411 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12412 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12413 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12414 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12415 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12416 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12417 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12418 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12419 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12420 { HCBT_DESTROYWND, hook },
12421 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12422 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12423 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12424 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12425 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12426 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
12427 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12428 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12429 { 0 }
12430 };
12431 static const struct message wm_popup_menu_3[] =
12432 {
12433 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12434 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12435 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12436 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12437 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12438 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12439 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12440 { WM_INITMENU, sent|lparam, 0, 0 },
12441 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12442 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12443 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12444 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12445 { HCBT_CREATEWND, hook },
12446 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12447 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12448 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12449 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12450 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12451 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12452 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12453 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12454 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12455 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12456 { HCBT_DESTROYWND, hook },
12457 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12458 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12459 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12460 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12461 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12462 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
12463 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12464 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12465 { 0 }
12466 };
12467
12468 static const struct message wm_single_menu_item[] =
12469 {
12470 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12471 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12472 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
12473 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
12474 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
12475 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
12476 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12477 { WM_INITMENU, sent|lparam, 0, 0 },
12478 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
12479 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12480 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12481 { WM_MENUCOMMAND, sent },
12482 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
12483 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
12484 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
12485 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
12486
12487 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
12488 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
12489 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
12490 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
12491 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
12492 { 0 }
12493 };
12494
12495 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12496 {
12497 if (message == WM_ENTERIDLE ||
12498 message == WM_INITMENU ||
12499 message == WM_INITMENUPOPUP ||
12500 message == WM_MENUSELECT ||
12501 message == WM_PARENTNOTIFY ||
12502 message == WM_ENTERMENULOOP ||
12503 message == WM_EXITMENULOOP ||
12504 message == WM_UNINITMENUPOPUP ||
12505 message == WM_KEYDOWN ||
12506 message == WM_KEYUP ||
12507 message == WM_CHAR ||
12508 message == WM_SYSKEYDOWN ||
12509 message == WM_SYSKEYUP ||
12510 message == WM_SYSCHAR ||
12511 message == WM_COMMAND ||
12512 message == WM_MENUCOMMAND)
12513 {
12514 struct recvd_message msg;
12515
12516 msg.hwnd = hwnd;
12517 msg.message = message;
12518 msg.flags = sent|wparam|lparam;
12519 msg.wParam = wp;
12520 msg.lParam = lp;
12521 msg.descr = "parent_menu_proc";
12522 add_message(&msg);
12523 }
12524
12525 return DefWindowProcA(hwnd, message, wp, lp);
12526 }
12527
12528 static void set_menu_style(HMENU hmenu, DWORD style)
12529 {
12530 MENUINFO mi;
12531 BOOL ret;
12532
12533 mi.cbSize = sizeof(mi);
12534 mi.fMask = MIM_STYLE;
12535 mi.dwStyle = style;
12536 SetLastError(0xdeadbeef);
12537 ret = pSetMenuInfo(hmenu, &mi);
12538 ok(ret, "SetMenuInfo error %u\n", GetLastError());
12539 }
12540
12541 static DWORD get_menu_style(HMENU hmenu)
12542 {
12543 MENUINFO mi;
12544 BOOL ret;
12545
12546 mi.cbSize = sizeof(mi);
12547 mi.fMask = MIM_STYLE;
12548 mi.dwStyle = 0;
12549 SetLastError(0xdeadbeef);
12550 ret = pGetMenuInfo(hmenu, &mi);
12551 ok(ret, "GetMenuInfo error %u\n", GetLastError());
12552
12553 return mi.dwStyle;
12554 }
12555
12556 static void test_menu_messages(void)
12557 {
12558 MSG msg;
12559 WNDCLASSA cls;
12560 HMENU hmenu, hmenu_popup;
12561 HWND hwnd;
12562 DWORD style;
12563
12564 if (!pGetMenuInfo || !pSetMenuInfo)
12565 {
12566 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
12567 return;
12568 }
12569 cls.style = 0;
12570 cls.lpfnWndProc = parent_menu_proc;
12571 cls.cbClsExtra = 0;
12572 cls.cbWndExtra = 0;
12573 cls.hInstance = GetModuleHandleA(0);
12574 cls.hIcon = 0;
12575 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
12576 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
12577 cls.lpszMenuName = NULL;
12578 cls.lpszClassName = "TestMenuClass";
12579 UnregisterClassA(cls.lpszClassName, cls.hInstance);
12580 if (!RegisterClassA(&cls)) assert(0);
12581
12582 SetLastError(0xdeadbeef);
12583 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12584 100, 100, 200, 200, 0, 0, 0, NULL);
12585 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
12586
12587 SetLastError(0xdeadbeef);
12588 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
12589 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
12590
12591 SetMenu(hwnd, hmenu);
12592 SetForegroundWindow( hwnd );
12593
12594 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
12595 style = get_menu_style(hmenu);
12596 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12597
12598 hmenu_popup = GetSubMenu(hmenu, 0);
12599 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12600 style = get_menu_style(hmenu_popup);
12601 ok(style == 0, "expected 0, got %u\n", style);
12602
12603 hmenu_popup = GetSubMenu(hmenu_popup, 0);
12604 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12605 style = get_menu_style(hmenu_popup);
12606 ok(style == 0, "expected 0, got %u\n", style);
12607
12608 /* Alt+E, Enter */
12609 trace("testing a popup menu command\n");
12610 flush_sequence();
12611 keybd_event(VK_MENU, 0, 0, 0);
12612 keybd_event('E', 0, 0, 0);
12613 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
12614 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12615 keybd_event(VK_RETURN, 0, 0, 0);
12616 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12617 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12618 {
12619 TranslateMessage(&msg);
12620 DispatchMessageA(&msg);
12621 }
12622 if (!sequence_cnt) /* we didn't get any message */
12623 {
12624 skip( "queuing key events not supported\n" );
12625 goto done;
12626 }
12627 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
12628 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
12629 {
12630 win_skip( "menu tracking through VK_MENU not supported\n" );
12631 goto done;
12632 }
12633 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
12634
12635 /* Alt+F, Right, Enter */
12636 trace("testing submenu of a popup menu command\n");
12637 flush_sequence();
12638 keybd_event(VK_MENU, 0, 0, 0);
12639 keybd_event('F', 0, 0, 0);
12640 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12641 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12642 keybd_event(VK_RIGHT, 0, 0, 0);
12643 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12644 keybd_event(VK_RETURN, 0, 0, 0);
12645 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12646 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12647 {
12648 TranslateMessage(&msg);
12649 DispatchMessageA(&msg);
12650 }
12651 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
12652
12653 trace("testing single menu item command\n");
12654 flush_sequence();
12655 keybd_event(VK_MENU, 0, 0, 0);
12656 keybd_event('Q', 0, 0, 0);
12657 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
12658 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12659 keybd_event(VK_ESCAPE, 0, 0, 0);
12660 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
12661 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12662 {
12663 TranslateMessage(&msg);
12664 DispatchMessageA(&msg);
12665 }
12666 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
12667
12668 set_menu_style(hmenu, 0);
12669 style = get_menu_style(hmenu);
12670 ok(style == 0, "expected 0, got %u\n", style);
12671
12672 hmenu_popup = GetSubMenu(hmenu, 0);
12673 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12674 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
12675 style = get_menu_style(hmenu_popup);
12676 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12677
12678 hmenu_popup = GetSubMenu(hmenu_popup, 0);
12679 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12680 style = get_menu_style(hmenu_popup);
12681 ok(style == 0, "expected 0, got %u\n", style);
12682
12683 /* Alt+F, Right, Enter */
12684 trace("testing submenu of a popup menu command\n");
12685 flush_sequence();
12686 keybd_event(VK_MENU, 0, 0, 0);
12687 keybd_event('F', 0, 0, 0);
12688 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12689 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12690 keybd_event(VK_RIGHT, 0, 0, 0);
12691 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12692 keybd_event(VK_RETURN, 0, 0, 0);
12693 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12694 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12695 {
12696 TranslateMessage(&msg);
12697 DispatchMessageA(&msg);
12698 }
12699 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
12700
12701 done:
12702 DestroyWindow(hwnd);
12703 DestroyMenu(hmenu);
12704 }
12705
12706
12707 static void test_paintingloop(void)
12708 {
12709 HWND hwnd;
12710
12711 paint_loop_done = 0;
12712 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
12713 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
12714 100, 100, 100, 100, 0, 0, 0, NULL );
12715 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
12716 ShowWindow(hwnd,SW_NORMAL);
12717 SetFocus(hwnd);
12718
12719 while (!paint_loop_done)
12720 {
12721 MSG msg;
12722 if (PeekMessageA(&msg, 0, 0, 0, 1))
12723 {
12724 TranslateMessage(&msg);
12725 DispatchMessageA(&msg);
12726 }
12727 }
12728 DestroyWindow(hwnd);
12729 }
12730
12731 static void test_defwinproc(void)
12732 {
12733 HWND hwnd;
12734 MSG msg;
12735 int gotwmquit = FALSE;
12736 hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
12737 assert(hwnd);
12738 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
12739 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
12740 if( msg.message == WM_QUIT) gotwmquit = TRUE;
12741 DispatchMessageA( &msg );
12742 }
12743 ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
12744 DestroyWindow( hwnd);
12745 }
12746
12747 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
12748 static void clear_clipboard_(int line, HWND hWnd)
12749 {
12750 BOOL succ;
12751 succ = OpenClipboard(hWnd);
12752 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
12753 succ = EmptyClipboard();
12754 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
12755 succ = CloseClipboard();
12756 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
12757 }
12758
12759 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
12760 static void expect_HWND_(int line, HWND expected, HWND got)
12761 {
12762 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
12763 }
12764
12765 static WNDPROC pOldViewerProc;
12766
12767 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
12768 {
12769 static BOOL recursion_guard;
12770
12771 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
12772 {
12773 recursion_guard = TRUE;
12774 clear_clipboard(hWnd);
12775 recursion_guard = FALSE;
12776 }
12777 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
12778 }
12779
12780 static void test_clipboard_viewers(void)
12781 {
12782 static struct message wm_change_cb_chain[] =
12783 {
12784 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
12785 { 0 }
12786 };
12787 static const struct message wm_clipboard_destroyed[] =
12788 {
12789 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12790 { 0 }
12791 };
12792 static struct message wm_clipboard_changed[] =
12793 {
12794 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12795 { 0 }
12796 };
12797 static struct message wm_clipboard_changed_and_owned[] =
12798 {
12799 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12800 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12801 { 0 }
12802 };
12803
12804 HINSTANCE hInst = GetModuleHandleA(NULL);
12805 HWND hWnd1, hWnd2, hWnd3;
12806 HWND hOrigViewer;
12807 HWND hRet;
12808
12809 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
12810 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12811 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12812 GetDesktopWindow(), NULL, hInst, NULL);
12813 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
12814 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12815 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12816 GetDesktopWindow(), NULL, hInst, NULL);
12817 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
12818 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12819 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12820 GetDesktopWindow(), NULL, hInst, NULL);
12821 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
12822 assert(hWnd1 && hWnd2 && hWnd3);
12823
12824 flush_sequence();
12825
12826 /* Test getting the clipboard viewer and setting the viewer to NULL. */
12827 hOrigViewer = GetClipboardViewer();
12828 hRet = SetClipboardViewer(NULL);
12829 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
12830 expect_HWND(hOrigViewer, hRet);
12831 expect_HWND(NULL, GetClipboardViewer());
12832
12833 /* Test registering hWnd1 as a viewer. */
12834 hRet = SetClipboardViewer(hWnd1);
12835 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12836 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
12837 expect_HWND(NULL, hRet);
12838 expect_HWND(hWnd1, GetClipboardViewer());
12839
12840 /* Test that changing the clipboard actually refreshes the registered viewer. */
12841 clear_clipboard(hWnd1);
12842 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12843 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
12844
12845 /* Again, but with different owner. */
12846 clear_clipboard(hWnd2);
12847 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
12848 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
12849
12850 /* Test re-registering same window. */
12851 hRet = SetClipboardViewer(hWnd1);
12852 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12853 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
12854 expect_HWND(hWnd1, hRet);
12855 expect_HWND(hWnd1, GetClipboardViewer());
12856
12857 /* Test ChangeClipboardChain. */
12858 ChangeClipboardChain(hWnd2, hWnd3);
12859 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12860 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
12861 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
12862 expect_HWND(hWnd1, GetClipboardViewer());
12863
12864 ChangeClipboardChain(hWnd2, NULL);
12865 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12866 wm_change_cb_chain[0].lParam = 0;
12867 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
12868 expect_HWND(hWnd1, GetClipboardViewer());
12869
12870 ChangeClipboardChain(NULL, hWnd2);
12871 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
12872 expect_HWND(hWnd1, GetClipboardViewer());
12873
12874 /* Actually change clipboard viewer with ChangeClipboardChain. */
12875 ChangeClipboardChain(hWnd1, hWnd2);
12876 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
12877 expect_HWND(hWnd2, GetClipboardViewer());
12878
12879 /* Test that no refresh messages are sent when viewer has unregistered. */
12880 clear_clipboard(hWnd2);
12881 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
12882
12883 /* Register hWnd1 again. */
12884 ChangeClipboardChain(hWnd2, hWnd1);
12885 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
12886 expect_HWND(hWnd1, GetClipboardViewer());
12887
12888 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
12889 * changes the clipboard. When this happens, the system shouldn't send
12890 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
12891 */
12892 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
12893 clear_clipboard(hWnd2);
12894 /* The clipboard owner is changed in recursive_viewer_proc: */
12895 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
12896 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
12897
12898 /* Test unregistering. */
12899 ChangeClipboardChain(hWnd1, NULL);
12900 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
12901 expect_HWND(NULL, GetClipboardViewer());
12902
12903 clear_clipboard(hWnd1);
12904 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
12905
12906 DestroyWindow(hWnd1);
12907 DestroyWindow(hWnd2);
12908 DestroyWindow(hWnd3);
12909 SetClipboardViewer(hOrigViewer);
12910 }
12911
12912 static void test_PostMessage(void)
12913 {
12914 static const struct
12915 {
12916 HWND hwnd;
12917 BOOL ret;
12918 } data[] =
12919 {
12920 { HWND_TOP /* 0 */, TRUE },
12921 { HWND_BROADCAST, TRUE },
12922 { HWND_BOTTOM, TRUE },
12923 { HWND_TOPMOST, TRUE },
12924 { HWND_NOTOPMOST, FALSE },
12925 { HWND_MESSAGE, FALSE },
12926 { (HWND)0xdeadbeef, FALSE }
12927 };
12928 int i;
12929 HWND hwnd;
12930 BOOL ret;
12931 MSG msg;
12932 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
12933
12934 SetLastError(0xdeadbeef);
12935 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12936 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
12937 {
12938 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
12939 return;
12940 }
12941 assert(hwnd);
12942
12943 flush_events();
12944
12945 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
12946 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
12947
12948 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
12949 {
12950 memset(&msg, 0xab, sizeof(msg));
12951 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
12952 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
12953 if (data[i].ret)
12954 {
12955 if (data[i].hwnd)
12956 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
12957 msg.wParam == 0x5678 && msg.lParam == 0x1234,
12958 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
12959 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
12960 else
12961 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
12962 msg.wParam == 0x1234 && msg.lParam == 0x5678,
12963 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
12964 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
12965 }
12966 }
12967
12968 DestroyWindow(hwnd);
12969 flush_events();
12970 }
12971
12972 static const struct
12973 {
12974 DWORD exp, broken;
12975 BOOL todo;
12976 } wait_idle_expect[] =
12977 {
12978 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12979 { WAIT_TIMEOUT, 0, FALSE },
12980 { WAIT_TIMEOUT, 0, FALSE },
12981 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12982 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12983 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
12984 { WAIT_TIMEOUT, 0, FALSE },
12985 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12986 { 0, 0, FALSE },
12987 { 0, 0, FALSE },
12988 /* 10 */ { 0, 0, FALSE },
12989 { 0, 0, FALSE },
12990 { 0, WAIT_TIMEOUT, FALSE },
12991 { 0, 0, FALSE },
12992 { 0, 0, FALSE },
12993 /* 15 */ { 0, 0, FALSE },
12994 { WAIT_TIMEOUT, 0, FALSE },
12995 { WAIT_TIMEOUT, 0, FALSE },
12996 { WAIT_TIMEOUT, 0, FALSE },
12997 { WAIT_TIMEOUT, 0, FALSE },
12998 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
12999 };
13000
13001 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
13002 {
13003 MSG msg;
13004
13005 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13006 Sleep( 200 );
13007 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13008 return 0;
13009 }
13010
13011 static void do_wait_idle_child( int arg )
13012 {
13013 WNDCLASSA cls;
13014 MSG msg;
13015 HWND hwnd = 0;
13016 HANDLE thread;
13017 DWORD id;
13018 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
13019 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
13020
13021 memset( &cls, 0, sizeof(cls) );
13022 cls.lpfnWndProc = DefWindowProcA;
13023 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
13024 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
13025 cls.lpszClassName = "TestClass";
13026 RegisterClassA( &cls );
13027
13028 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
13029
13030 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
13031 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
13032
13033 switch (arg)
13034 {
13035 case 0:
13036 SetEvent( start_event );
13037 break;
13038 case 1:
13039 SetEvent( start_event );
13040 Sleep( 200 );
13041 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13042 break;
13043 case 2:
13044 SetEvent( start_event );
13045 Sleep( 200 );
13046 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13047 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
13048 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13049 break;
13050 case 3:
13051 SetEvent( start_event );
13052 Sleep( 200 );
13053 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
13054 break;
13055 case 4:
13056 SetEvent( start_event );
13057 Sleep( 200 );
13058 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13059 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
13060 break;
13061 case 5:
13062 SetEvent( start_event );
13063 Sleep( 200 );
13064 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13065 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13066 break;
13067 case 6:
13068 SetEvent( start_event );
13069 Sleep( 200 );
13070 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13071 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
13072 {
13073 GetMessageA( &msg, 0, 0, 0 );
13074 DispatchMessageA( &msg );
13075 }
13076 break;
13077 case 7:
13078 SetEvent( start_event );
13079 Sleep( 200 );
13080 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13081 SetTimer( hwnd, 3, 1, NULL );
13082 Sleep( 200 );
13083 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
13084 break;
13085 case 8:
13086 SetEvent( start_event );
13087 Sleep( 200 );
13088 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13089 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13090 break;
13091 case 9:
13092 SetEvent( start_event );
13093 Sleep( 200 );
13094 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13095 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13096 for (;;) GetMessageA( &msg, 0, 0, 0 );
13097 break;
13098 case 10:
13099 SetEvent( start_event );
13100 Sleep( 200 );
13101 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
13102 SetTimer( hwnd, 3, 1, NULL );
13103 Sleep( 200 );
13104 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
13105 break;
13106 case 11:
13107 SetEvent( start_event );
13108 Sleep( 200 );
13109 return; /* exiting the process makes WaitForInputIdle return success too */
13110 case 12:
13111 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13112 Sleep( 200 );
13113 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
13114 SetEvent( start_event );
13115 break;
13116 case 13:
13117 SetEvent( start_event );
13118 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13119 Sleep( 200 );
13120 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
13121 WaitForSingleObject( thread, 10000 );
13122 CloseHandle( thread );
13123 break;
13124 case 14:
13125 SetEvent( start_event );
13126 Sleep( 200 );
13127 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
13128 break;
13129 case 15:
13130 SetEvent( start_event );
13131 Sleep( 200 );
13132 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
13133 break;
13134 case 16:
13135 SetEvent( start_event );
13136 Sleep( 200 );
13137 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
13138 break;
13139 case 17:
13140 SetEvent( start_event );
13141 Sleep( 200 );
13142 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
13143 break;
13144 case 18:
13145 SetEvent( start_event );
13146 Sleep( 200 );
13147 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
13148 break;
13149 case 19:
13150 SetEvent( start_event );
13151 Sleep( 200 );
13152 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
13153 break;
13154 case 20:
13155 SetEvent( start_event );
13156 Sleep( 200 );
13157 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
13158 break;
13159 }
13160 WaitForSingleObject( end_event, 2000 );
13161 CloseHandle( start_event );
13162 CloseHandle( end_event );
13163 if (hwnd) DestroyWindow( hwnd );
13164 }
13165
13166 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
13167 {
13168 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
13169 return DefWindowProcA( hwnd, msg, wp, lp );
13170 }
13171
13172 static DWORD CALLBACK wait_idle_thread( void *arg )
13173 {
13174 WNDCLASSA cls;
13175 MSG msg;
13176 HWND hwnd;
13177
13178 memset( &cls, 0, sizeof(cls) );
13179 cls.lpfnWndProc = wait_idle_proc;
13180 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
13181 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
13182 cls.lpszClassName = "TestClass";
13183 RegisterClassA( &cls );
13184
13185 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
13186 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
13187 DestroyWindow(hwnd);
13188 return 0;
13189 }
13190
13191 static void test_WaitForInputIdle( char *argv0 )
13192 {
13193 char path[MAX_PATH];
13194 PROCESS_INFORMATION pi;
13195 STARTUPINFOA startup;
13196 BOOL ret;
13197 HANDLE start_event, end_event, thread;
13198 unsigned int i;
13199 DWORD id;
13200 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
13201 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
13202 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
13203
13204 if (console_app) /* build the test with -mwindows for better coverage */
13205 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
13206
13207 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
13208 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
13209 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
13210 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
13211
13212 memset( &startup, 0, sizeof(startup) );
13213 startup.cb = sizeof(startup);
13214 startup.dwFlags = STARTF_USESHOWWINDOW;
13215 startup.wShowWindow = SW_SHOWNORMAL;
13216
13217 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
13218
13219 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
13220 {
13221 ResetEvent( start_event );
13222 ResetEvent( end_event );
13223 sprintf( path, "%s msg %u", argv0, i );
13224 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
13225 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
13226 if (ret)
13227 {
13228 ret = WaitForSingleObject( start_event, 5000 );
13229 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
13230 if (ret == WAIT_OBJECT_0)
13231 {
13232 ret = WaitForInputIdle( pi.hProcess, 1000 );
13233 if (ret == WAIT_FAILED)
13234 ok( console_app ||
13235 ret == wait_idle_expect[i].exp ||
13236 broken(ret == wait_idle_expect[i].broken),
13237 "%u: WaitForInputIdle error %08x expected %08x\n",
13238 i, ret, wait_idle_expect[i].exp );
13239 else if (wait_idle_expect[i].todo)
13240 todo_wine
13241 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
13242 "%u: WaitForInputIdle error %08x expected %08x\n",
13243 i, ret, wait_idle_expect[i].exp );
13244 else
13245 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
13246 "%u: WaitForInputIdle error %08x expected %08x\n",
13247 i, ret, wait_idle_expect[i].exp );
13248 SetEvent( end_event );
13249 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
13250 }
13251 TerminateProcess( pi.hProcess, 0 ); /* just in case */
13252 winetest_wait_child_process( pi.hProcess );
13253 ret = WaitForInputIdle( pi.hProcess, 100 );
13254 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
13255 CloseHandle( pi.hProcess );
13256 CloseHandle( pi.hThread );
13257 }
13258 }
13259 CloseHandle( start_event );
13260 PostThreadMessageA( id, WM_QUIT, 0, 0 );
13261 WaitForSingleObject( thread, 10000 );
13262 CloseHandle( thread );
13263 }
13264
13265 static const struct message WmSetParentSeq_1[] = {
13266 { WM_SHOWWINDOW, sent|wparam, 0 },
13267 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13268 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
13269 { WM_CHILDACTIVATE, sent },
13270 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
13271 { WM_MOVE, sent|defwinproc|wparam, 0 },
13272 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13273 { WM_SHOWWINDOW, sent|wparam, 1 },
13274 { 0 }
13275 };
13276
13277 static const struct message WmSetParentSeq_2[] = {
13278 { WM_SHOWWINDOW, sent|wparam, 0 },
13279 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13280 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
13281 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13282 { HCBT_SETFOCUS, hook|optional },
13283 { WM_NCACTIVATE, sent|wparam|optional, 0 },
13284 { WM_ACTIVATE, sent|wparam|optional, 0 },
13285 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13286 { WM_KILLFOCUS, sent|wparam, 0 },
13287 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13288 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
13289 { HCBT_ACTIVATE, hook|optional },
13290 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
13291 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13292 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13293 { WM_ACTIVATE, sent|wparam|optional, 1 },
13294 { HCBT_SETFOCUS, hook|optional },
13295 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13296 { WM_SETFOCUS, sent|optional|defwinproc },
13297 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
13298 { WM_MOVE, sent|defwinproc|wparam, 0 },
13299 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13300 { WM_SHOWWINDOW, sent|wparam, 1 },
13301 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13302 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
13303 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13304 { 0 }
13305 };
13306
13307
13308 static void test_SetParent(void)
13309 {
13310 HWND parent1, parent2, child, popup;
13311 RECT rc, rc_old;
13312
13313 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13314 100, 100, 200, 200, 0, 0, 0, NULL);
13315 ok(parent1 != 0, "Failed to create parent1 window\n");
13316
13317 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13318 400, 100, 200, 200, 0, 0, 0, NULL);
13319 ok(parent2 != 0, "Failed to create parent2 window\n");
13320
13321 /* WS_CHILD window */
13322 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
13323 10, 10, 150, 150, parent1, 0, 0, NULL);
13324 ok(child != 0, "Failed to create child window\n");
13325
13326 GetWindowRect(parent1, &rc);
13327 trace("parent1 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13328 GetWindowRect(child, &rc_old);
13329 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
13330 trace("child (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13331
13332 flush_sequence();
13333
13334 SetParent(child, parent2);
13335 flush_events();
13336 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
13337
13338 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13339 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
13340
13341 GetWindowRect(parent2, &rc);
13342 trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13343 GetWindowRect(child, &rc);
13344 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
13345 trace("child (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13346
13347 ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13348 rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13349 rc.left, rc.top, rc.right, rc.bottom );
13350
13351 /* WS_POPUP window */
13352 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
13353 20, 20, 100, 100, 0, 0, 0, NULL);
13354 ok(popup != 0, "Failed to create popup window\n");
13355
13356 GetWindowRect(popup, &rc_old);
13357 trace("popup (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13358
13359 flush_sequence();
13360
13361 SetParent(popup, child);
13362 flush_events();
13363 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
13364
13365 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13366 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
13367
13368 GetWindowRect(child, &rc);
13369 trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13370 GetWindowRect(popup, &rc);
13371 MapWindowPoints(0, child, (POINT *)&rc, 2);
13372 trace("popup (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13373
13374 ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13375 rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13376 rc.left, rc.top, rc.right, rc.bottom );
13377
13378 DestroyWindow(popup);
13379 DestroyWindow(child);
13380 DestroyWindow(parent1);
13381 DestroyWindow(parent2);
13382
13383 flush_sequence();
13384 }
13385
13386 static const struct message WmKeyReleaseOnly[] = {
13387 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
13388 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
13389 { 0 }
13390 };
13391 static const struct message WmKeyPressNormal[] = {
13392 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
13393 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
13394 { 0 }
13395 };
13396 static const struct message WmKeyPressRepeat[] = {
13397 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
13398 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
13399 { 0 }
13400 };
13401 static const struct message WmKeyReleaseNormal[] = {
13402 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
13403 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
13404 { 0 }
13405 };
13406
13407 static void test_keyflags(void)
13408 {
13409 HWND test_window;
13410 SHORT key_state;
13411 BYTE keyboard_state[256];
13412 MSG msg;
13413
13414 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13415 100, 100, 200, 200, 0, 0, 0, NULL);
13416
13417 flush_events();
13418 flush_sequence();
13419
13420 /* keyup without a keydown */
13421 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13422 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13423 DispatchMessageA(&msg);
13424 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
13425
13426 key_state = GetAsyncKeyState(0x41);
13427 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13428
13429 key_state = GetKeyState(0x41);
13430 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13431
13432 /* keydown */
13433 keybd_event(0x41, 0, 0, 0);
13434 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13435 DispatchMessageA(&msg);
13436 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
13437
13438 key_state = GetAsyncKeyState(0x41);
13439 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13440
13441 key_state = GetKeyState(0x41);
13442 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13443
13444 /* keydown repeat */
13445 keybd_event(0x41, 0, 0, 0);
13446 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13447 DispatchMessageA(&msg);
13448 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
13449
13450 key_state = GetAsyncKeyState(0x41);
13451 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13452
13453 key_state = GetKeyState(0x41);
13454 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13455
13456 /* keyup */
13457 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13458 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13459 DispatchMessageA(&msg);
13460 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
13461
13462 key_state = GetAsyncKeyState(0x41);
13463 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13464
13465 key_state = GetKeyState(0x41);
13466 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13467
13468 /* set the key state in this thread */
13469 GetKeyboardState(keyboard_state);
13470 keyboard_state[0x41] = 0x80;
13471 SetKeyboardState(keyboard_state);
13472
13473 key_state = GetAsyncKeyState(0x41);
13474 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13475
13476 /* keydown */
13477 keybd_event(0x41, 0, 0, 0);
13478 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13479 DispatchMessageA(&msg);
13480 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
13481
13482 key_state = GetAsyncKeyState(0x41);
13483 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13484
13485 key_state = GetKeyState(0x41);
13486 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13487
13488 /* clear the key state in this thread */
13489 GetKeyboardState(keyboard_state);
13490 keyboard_state[0x41] = 0;
13491 SetKeyboardState(keyboard_state);
13492
13493 key_state = GetAsyncKeyState(0x41);
13494 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13495
13496 /* keyup */
13497 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13498 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13499 DispatchMessageA(&msg);
13500 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
13501
13502 key_state = GetAsyncKeyState(0x41);
13503 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13504
13505 key_state = GetKeyState(0x41);
13506 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13507
13508 DestroyWindow(test_window);
13509 flush_sequence();
13510 }
13511
13512 static const struct message WmHotkeyPressLWIN[] = {
13513 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13514 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13515 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13516 { 0 }
13517 };
13518 static const struct message WmHotkeyPress[] = {
13519 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13520 { WM_HOTKEY, sent|wparam, 5 },
13521 { 0 }
13522 };
13523 static const struct message WmHotkeyRelease[] = {
13524 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13525 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
13526 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
13527 { 0 }
13528 };
13529 static const struct message WmHotkeyReleaseLWIN[] = {
13530 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13531 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13532 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13533 { 0 }
13534 };
13535 static const struct message WmHotkeyCombined[] = {
13536 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13537 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13538 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13539 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13540 { WM_APP, sent, 0, 0 },
13541 { WM_HOTKEY, sent|wparam, 5 },
13542 { WM_APP+1, sent, 0, 0 },
13543 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13544 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13545 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13546 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13547 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13548 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13549 { 0 }
13550 };
13551 static const struct message WmHotkeyPrevious[] = {
13552 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13553 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13554 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13555 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13556 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13557 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13558 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
13559 { WM_KEYDOWN, sent|lparam, 0, 1 },
13560 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
13561 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
13562 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13563 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13564 { 0 }
13565 };
13566 static const struct message WmHotkeyNew[] = {
13567 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13568 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13569 { WM_HOTKEY, sent|wparam, 5 },
13570 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13571 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13572 { 0 }
13573 };
13574
13575 static int hotkey_letter;
13576
13577 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
13578 {
13579 struct recvd_message msg;
13580
13581 if (nCode == HC_ACTION)
13582 {
13583 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
13584
13585 msg.hwnd = 0;
13586 msg.message = wParam;
13587 msg.flags = kbd_hook|wparam|lparam;
13588 msg.wParam = kdbhookstruct->vkCode;
13589 msg.lParam = kdbhookstruct->flags;
13590 msg.descr = "KeyboardHookProc";
13591 add_message(&msg);
13592
13593 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
13594 {
13595 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
13596 "unexpected keycode %x\n", kdbhookstruct->vkCode);
13597 }
13598 }
13599
13600 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
13601 }
13602
13603 static void test_hotkey(void)
13604 {
13605 HWND test_window, taskbar_window;
13606 BOOL ret;
13607 MSG msg;
13608 DWORD queue_status;
13609 SHORT key_state;
13610
13611 SetLastError(0xdeadbeef);
13612 ret = UnregisterHotKey(NULL, 0);
13613 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13614 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13615 "unexpected error %d\n", GetLastError());
13616
13617 if (ret == TRUE)
13618 {
13619 skip("hotkeys not supported\n");
13620 return;
13621 }
13622
13623 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13624 100, 100, 200, 200, 0, 0, 0, NULL);
13625
13626 flush_sequence();
13627
13628 SetLastError(0xdeadbeef);
13629 ret = UnregisterHotKey(test_window, 0);
13630 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13631 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13632 "unexpected error %d\n", GetLastError());
13633
13634 /* Search for a Windows Key + letter combination that hasn't been registered */
13635 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
13636 {
13637 SetLastError(0xdeadbeef);
13638 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13639
13640 if (ret == TRUE)
13641 {
13642 break;
13643 }
13644 else
13645 {
13646 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13647 "unexpected error %d\n", GetLastError());
13648 }
13649 }
13650
13651 if (hotkey_letter == 0x52)
13652 {
13653 ok(0, "Couldn't find any free Windows Key + letter combination\n");
13654 goto end;
13655 }
13656
13657 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
13658 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
13659
13660 /* Same key combination, different id */
13661 SetLastError(0xdeadbeef);
13662 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
13663 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13664 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13665 "unexpected error %d\n", GetLastError());
13666
13667 /* Same key combination, different window */
13668 SetLastError(0xdeadbeef);
13669 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13670 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13671 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13672 "unexpected error %d\n", GetLastError());
13673
13674 /* Register the same hotkey twice */
13675 SetLastError(0xdeadbeef);
13676 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13677 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13678 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13679 "unexpected error %d\n", GetLastError());
13680
13681 /* Window on another thread */
13682 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
13683 if (!taskbar_window)
13684 {
13685 skip("no taskbar?\n");
13686 }
13687 else
13688 {
13689 SetLastError(0xdeadbeef);
13690 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
13691 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13692 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
13693 "unexpected error %d\n", GetLastError());
13694 }
13695
13696 /* Inject the appropriate key sequence */
13697 keybd_event(VK_LWIN, 0, 0, 0);
13698 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13699 DispatchMessageA(&msg);
13700 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
13701
13702 keybd_event(hotkey_letter, 0, 0, 0);
13703 queue_status = GetQueueStatus(QS_HOTKEY);
13704 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13705 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13706 {
13707 if (msg.message == WM_HOTKEY)
13708 {
13709 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13710 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13711 }
13712 DispatchMessageA(&msg);
13713 }
13714 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
13715
13716 queue_status = GetQueueStatus(QS_HOTKEY);
13717 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
13718
13719 key_state = GetAsyncKeyState(hotkey_letter);
13720 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13721
13722 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13723 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13724 DispatchMessageA(&msg);
13725 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
13726
13727 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13728 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13729 DispatchMessageA(&msg);
13730 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
13731
13732 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
13733 PostMessageA(test_window, WM_HOTKEY, 0, 0);
13734 queue_status = GetQueueStatus(QS_HOTKEY);
13735 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13736 queue_status = GetQueueStatus(QS_POSTMESSAGE);
13737 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
13738 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13739 DispatchMessageA(&msg);
13740 flush_sequence();
13741
13742 /* Send and process all messages at once */
13743 PostMessageA(test_window, WM_APP, 0, 0);
13744 keybd_event(VK_LWIN, 0, 0, 0);
13745 keybd_event(hotkey_letter, 0, 0, 0);
13746 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13747 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13748
13749 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13750 {
13751 if (msg.message == WM_HOTKEY)
13752 {
13753 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13754 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13755 }
13756 DispatchMessageA(&msg);
13757 }
13758 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
13759
13760 /* Register same hwnd/id with different key combination */
13761 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
13762 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13763
13764 /* Previous key combination does not work */
13765 keybd_event(VK_LWIN, 0, 0, 0);
13766 keybd_event(hotkey_letter, 0, 0, 0);
13767 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13768 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13769
13770 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13771 DispatchMessageA(&msg);
13772 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
13773
13774 /* New key combination works */
13775 keybd_event(hotkey_letter, 0, 0, 0);
13776 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13777
13778 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13779 {
13780 if (msg.message == WM_HOTKEY)
13781 {
13782 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13783 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13784 }
13785 DispatchMessageA(&msg);
13786 }
13787 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
13788
13789 /* Unregister hotkey properly */
13790 ret = UnregisterHotKey(test_window, 5);
13791 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13792
13793 /* Unregister hotkey again */
13794 SetLastError(0xdeadbeef);
13795 ret = UnregisterHotKey(test_window, 5);
13796 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13797 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13798 "unexpected error %d\n", GetLastError());
13799
13800 /* Register thread hotkey */
13801 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13802 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
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 {
13808 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13809 DispatchMessageA(&msg);
13810 }
13811 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
13812
13813 keybd_event(hotkey_letter, 0, 0, 0);
13814 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13815 {
13816 if (msg.message == WM_HOTKEY)
13817 {
13818 struct recvd_message message;
13819 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
13820 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13821 message.message = msg.message;
13822 message.flags = sent|wparam|lparam;
13823 message.wParam = msg.wParam;
13824 message.lParam = msg.lParam;
13825 message.descr = "test_hotkey thread message";
13826 add_message(&message);
13827 }
13828 else
13829 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13830 DispatchMessageA(&msg);
13831 }
13832 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
13833
13834 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13835 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13836 {
13837 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13838 DispatchMessageA(&msg);
13839 }
13840 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
13841
13842 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13843 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
13844 {
13845 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13846 DispatchMessageA(&msg);
13847 }
13848 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
13849
13850 /* Unregister thread hotkey */
13851 ret = UnregisterHotKey(NULL, 5);
13852 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13853
13854 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
13855 hKBD_hook = NULL;
13856
13857 end:
13858 UnregisterHotKey(NULL, 5);
13859 UnregisterHotKey(test_window, 5);
13860 DestroyWindow(test_window);
13861 flush_sequence();
13862 }
13863
13864
13865 static const struct message WmSetFocus_1[] = {
13866 { HCBT_SETFOCUS, hook }, /* child */
13867 { HCBT_ACTIVATE, hook }, /* parent */
13868 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
13869 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
13870 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
13871 { WM_NCACTIVATE, sent|parent },
13872 { WM_GETTEXT, sent|defwinproc|parent|optional },
13873 { WM_GETTEXT, sent|defwinproc|parent|optional },
13874 { WM_ACTIVATE, sent|wparam|parent, 1 },
13875 { HCBT_SETFOCUS, hook }, /* parent */
13876 { WM_SETFOCUS, sent|defwinproc|parent },
13877 { WM_KILLFOCUS, sent|parent },
13878 { WM_SETFOCUS, sent },
13879 { 0 }
13880 };
13881 static const struct message WmSetFocus_2[] = {
13882 { HCBT_SETFOCUS, hook }, /* parent */
13883 { WM_KILLFOCUS, sent },
13884 { WM_SETFOCUS, sent|parent },
13885 { 0 }
13886 };
13887 static const struct message WmSetFocus_3[] = {
13888 { HCBT_SETFOCUS, hook }, /* child */
13889 { 0 }
13890 };
13891 static const struct message WmSetFocus_4[] = {
13892 { 0 }
13893 };
13894
13895 static void test_SetFocus(void)
13896 {
13897 HWND parent, old_parent, child, old_focus, old_active;
13898 MSG msg;
13899 struct wnd_event wnd_event;
13900 HANDLE hthread;
13901 DWORD ret, tid;
13902
13903 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
13904 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
13905 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
13906 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
13907 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
13908 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
13909 CloseHandle(wnd_event.start_event);
13910
13911 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13912 0, 0, 0, 0, 0, 0, 0, NULL);
13913 ok(parent != 0, "failed to create parent window\n");
13914 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
13915 0, 0, 0, 0, parent, 0, 0, NULL);
13916 ok(child != 0, "failed to create child window\n");
13917
13918 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
13919
13920 SetFocus(0);
13921 SetActiveWindow(0);
13922
13923 flush_events();
13924 flush_sequence();
13925
13926 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13927 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13928
13929 log_all_parent_messages++;
13930
13931 old_focus = SetFocus(child);
13932 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13933 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
13934 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13935 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13936 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
13937
13938 old_focus = SetFocus(parent);
13939 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13940 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
13941 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
13942 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13943 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13944
13945 SetLastError(0xdeadbeef);
13946 old_focus = SetFocus((HWND)0xdeadbeef);
13947 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13948 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
13949 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13950 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
13951 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13952 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13953 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13954
13955 SetLastError(0xdeadbeef);
13956 old_focus = SetFocus(GetDesktopWindow());
13957 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
13958 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
13959 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13960 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
13961 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13962 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13963 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13964
13965 SetLastError(0xdeadbeef);
13966 old_focus = SetFocus(wnd_event.hwnd);
13967 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
13968 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
13969 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13970 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
13971 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13972 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13973 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13974
13975 SetLastError(0xdeadbeef);
13976 old_active = SetActiveWindow((HWND)0xdeadbeef);
13977 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13978 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
13979 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13980 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
13981 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
13982 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13983 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13984
13985 SetLastError(0xdeadbeef);
13986 old_active = SetActiveWindow(GetDesktopWindow());
13987 todo_wine
13988 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13989 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13990 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
13991 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
13992 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13993 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13994
13995 SetLastError(0xdeadbeef);
13996 old_active = SetActiveWindow(wnd_event.hwnd);
13997 todo_wine
13998 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13999 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14000 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
14001 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
14002 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14003 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14004
14005 SetLastError(0xdeadbeef);
14006 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
14007 ok(ret, "AttachThreadInput error %d\n", GetLastError());
14008
14009 todo_wine {
14010 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14011 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14012 }
14013 flush_events();
14014 flush_sequence();
14015
14016 old_focus = SetFocus(wnd_event.hwnd);
14017 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14018 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
14019 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
14020 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
14021
14022 old_focus = SetFocus(parent);
14023 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14024 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
14025 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14026 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14027
14028 flush_events();
14029 flush_sequence();
14030
14031 old_active = SetActiveWindow(wnd_event.hwnd);
14032 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14033 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
14034 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
14035 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
14036
14037 SetLastError(0xdeadbeef);
14038 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
14039 ok(ret, "AttachThreadInput error %d\n", GetLastError());
14040
14041 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
14042 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
14043
14044 old_parent = SetParent(child, GetDesktopWindow());
14045 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
14046
14047 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
14048 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
14049
14050 old_focus = SetFocus(parent);
14051 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14052 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
14053 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14054 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14055
14056 flush_events();
14057 flush_sequence();
14058
14059 SetLastError(0xdeadbeef);
14060 old_focus = SetFocus(child);
14061 todo_wine
14062 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
14063 broken(GetLastError() == 0) /* XP */ ||
14064 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
14065 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14066 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
14067 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
14068 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14069 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14070
14071 SetLastError(0xdeadbeef);
14072 old_active = SetActiveWindow(child);
14073 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
14074 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
14075 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
14076 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
14077 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
14078 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
14079
14080 log_all_parent_messages--;
14081
14082 DestroyWindow(child);
14083 DestroyWindow(parent);
14084
14085 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
14086 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
14087 ret = WaitForSingleObject(hthread, INFINITE);
14088 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
14089 CloseHandle(hthread);
14090 }
14091
14092 static const struct message WmSetLayeredStyle[] = {
14093 { WM_STYLECHANGING, sent },
14094 { WM_STYLECHANGED, sent },
14095 { WM_GETTEXT, sent|defwinproc|optional },
14096 { 0 }
14097 };
14098
14099 static const struct message WmSetLayeredStyle2[] = {
14100 { WM_STYLECHANGING, sent },
14101 { WM_STYLECHANGED, sent },
14102 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14103 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
14104 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14105 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
14106 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
14107 { 0 }
14108 };
14109
14110 struct layered_window_info
14111 {
14112 HWND hwnd;
14113 HDC hdc;
14114 SIZE size;
14115 HANDLE event;
14116 BOOL ret;
14117 };
14118
14119 static DWORD CALLBACK update_layered_proc( void *param )
14120 {
14121 struct layered_window_info *info = param;
14122 POINT src = { 0, 0 };
14123
14124 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
14125 info->hdc, &src, 0, NULL, ULW_OPAQUE );
14126 ok( info->ret, "failed\n");
14127 SetEvent( info->event );
14128 return 0;
14129 }
14130
14131 static void test_layered_window(void)
14132 {
14133 HWND hwnd;
14134 HDC hdc;
14135 HBITMAP bmp;
14136 BOOL ret;
14137 SIZE size;
14138 POINT pos, src;
14139 RECT rect, client;
14140 HANDLE thread;
14141 DWORD tid;
14142 struct layered_window_info info;
14143
14144 if (!pUpdateLayeredWindow)
14145 {
14146 win_skip( "UpdateLayeredWindow not supported\n" );
14147 return;
14148 }
14149
14150 hdc = CreateCompatibleDC( 0 );
14151 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
14152 SelectObject( hdc, bmp );
14153
14154 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
14155 100, 100, 300, 300, 0, 0, 0, NULL);
14156 ok( hwnd != 0, "failed to create window\n" );
14157 ShowWindow( hwnd, SW_SHOWNORMAL );
14158 UpdateWindow( hwnd );
14159 flush_events();
14160 flush_sequence();
14161
14162 GetWindowRect( hwnd, &rect );
14163 GetClientRect( hwnd, &client );
14164 ok( client.right < rect.right - rect.left, "wrong client area\n" );
14165 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
14166
14167 src.x = src.y = 0;
14168 pos.x = pos.y = 300;
14169 size.cx = size.cy = 250;
14170 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14171 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14172 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
14173 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
14174 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
14175
14176 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14177 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14178 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14179 GetWindowRect( hwnd, &rect );
14180 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
14181 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14182 GetClientRect( hwnd, &rect );
14183 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
14184 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14185
14186 size.cx = 150;
14187 pos.y = 200;
14188 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14189 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14190 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14191 GetWindowRect( hwnd, &rect );
14192 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
14193 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14194 GetClientRect( hwnd, &rect );
14195 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
14196 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14197
14198 SetWindowLongA( hwnd, GWL_STYLE,
14199 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
14200 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
14201
14202 size.cx = 200;
14203 pos.x = 200;
14204 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14205 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
14206 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
14207 GetWindowRect( hwnd, &rect );
14208 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
14209 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14210 GetClientRect( hwnd, &rect );
14211 ok( (rect.right == 200 && rect.bottom == 250) ||
14212 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
14213 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14214
14215 size.cx = 0;
14216 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14217 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14218 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(ERROR_MR_MID_NOT_FOUND) /* win7 */,
14219 "wrong error %u\n", GetLastError() );
14220 size.cx = 1;
14221 size.cy = -1;
14222 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
14223 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
14224 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
14225
14226 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
14227 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
14228 GetWindowRect( hwnd, &rect );
14229 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
14230 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14231 GetClientRect( hwnd, &rect );
14232 ok( (rect.right == 200 && rect.bottom == 250) ||
14233 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
14234 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14235
14236 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
14237 info.hwnd = hwnd;
14238 info.hdc = hdc;
14239 info.size.cx = 250;
14240 info.size.cy = 300;
14241 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
14242 info.ret = FALSE;
14243 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
14244 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
14245 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
14246 WaitForSingleObject( thread, 1000 );
14247 CloseHandle( thread );
14248 GetWindowRect( hwnd, &rect );
14249 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
14250 "wrong window rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14251 GetClientRect( hwnd, &rect );
14252 ok( (rect.right == 250 && rect.bottom == 300) ||
14253 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
14254 "wrong client rect %d,%d,%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
14255
14256 DestroyWindow( hwnd );
14257 DeleteDC( hdc );
14258 DeleteObject( bmp );
14259 }
14260
14261 static void init_funcs(void)
14262 {
14263 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
14264
14265 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
14266 X(ActivateActCtx);
14267 X(CreateActCtxW);
14268 X(DeactivateActCtx);
14269 X(GetCurrentActCtx);
14270 X(ReleaseActCtx);
14271 #undef X
14272 }
14273
14274 START_TEST(msg)
14275 {
14276 char **test_argv;
14277 BOOL ret;
14278 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
14279 HMODULE hModuleImm32;
14280 BOOL (WINAPI *pImmDisableIME)(DWORD);
14281 int argc;
14282
14283 init_funcs();
14284
14285 argc = winetest_get_mainargs( &test_argv );
14286 if (argc >= 3)
14287 {
14288 unsigned int arg;
14289 /* Child process. */
14290 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
14291 do_wait_idle_child( arg );
14292 return;
14293 }
14294
14295 init_procs();
14296
14297 hModuleImm32 = LoadLibraryA("imm32.dll");
14298 if (hModuleImm32) {
14299 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
14300 if (pImmDisableIME)
14301 pImmDisableIME(0);
14302 }
14303 pImmDisableIME = NULL;
14304 FreeLibrary(hModuleImm32);
14305
14306 if (!RegisterWindowClasses()) assert(0);
14307
14308 if (pSetWinEventHook)
14309 {
14310 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
14311 GetModuleHandleA(0), win_event_proc,
14312 0, GetCurrentThreadId(),
14313 WINEVENT_INCONTEXT);
14314 if (pIsWinEventHookInstalled && hEvent_hook)
14315 {
14316 UINT event;
14317 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
14318 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
14319 }
14320 }
14321 if (!hEvent_hook) win_skip( "no win event hook support\n" );
14322
14323 cbt_hook_thread_id = GetCurrentThreadId();
14324 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
14325 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
14326
14327 test_winevents();
14328
14329 /* Fix message sequences before removing 4 lines below */
14330 #if 1
14331 if (pUnhookWinEvent && hEvent_hook)
14332 {
14333 ret = pUnhookWinEvent(hEvent_hook);
14334 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14335 pUnhookWinEvent = 0;
14336 }
14337 hEvent_hook = 0;
14338 #endif
14339
14340 test_SetFocus();
14341 test_SetParent();
14342 test_PostMessage();
14343 test_ShowWindow();
14344 test_PeekMessage();
14345 test_PeekMessage2();
14346 test_WaitForInputIdle( test_argv[0] );
14347 test_scrollwindowex();
14348 test_messages();
14349 test_setwindowpos();
14350 test_showwindow();
14351 invisible_parent_tests();
14352 test_mdi_messages();
14353 test_button_messages();
14354 test_static_messages();
14355 test_listbox_messages();
14356 test_combobox_messages();
14357 test_wmime_keydown_message();
14358 test_paint_messages();
14359 // test_interthread_messages(); ReactOS ActivateActCtx seems to be broken.
14360 test_message_conversion();
14361 test_accelerators();
14362 test_timers();
14363 test_timers_no_wnd();
14364 if (hCBT_hook) test_set_hook();
14365 test_DestroyWindow();
14366 test_DispatchMessage();
14367 test_SendMessageTimeout();
14368 test_edit_messages();
14369 test_quit_message();
14370 test_SetActiveWindow();
14371
14372 if (!pTrackMouseEvent)
14373 win_skip("TrackMouseEvent is not available\n");
14374 else
14375 test_TrackMouseEvent();
14376
14377 test_SetWindowRgn();
14378 test_sys_menu();
14379 test_dialog_messages();
14380 test_EndDialog();
14381 test_nullCallback();
14382 test_dbcs_wm_char();
14383 test_unicode_wm_char();
14384 test_menu_messages();
14385 test_paintingloop();
14386 test_defwinproc();
14387 test_clipboard_viewers();
14388 test_keyflags();
14389 test_hotkey();
14390 test_layered_window();
14391 /* keep it the last test, under Windows it tends to break the tests
14392 * which rely on active/foreground windows being correct.
14393 */
14394 test_SetForegroundWindow();
14395
14396 UnhookWindowsHookEx(hCBT_hook);
14397 if (pUnhookWinEvent && hEvent_hook)
14398 {
14399 ret = pUnhookWinEvent(hEvent_hook);
14400 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
14401 SetLastError(0xdeadbeef);
14402 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
14403 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
14404 GetLastError() == 0xdeadbeef, /* Win9x */
14405 "unexpected error %d\n", GetLastError());
14406 }
14407 }